Completed
Push — master ( abc512...672d79 )
by Eugene
06:40
created

ConnectionTest::testConnectInvalidHost()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the tarantool/client package.
5
 *
6
 * (c) Eugene Leonovich <[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
declare(strict_types=1);
13
14
namespace Tarantool\Client\Tests\Integration\Connection;
15
16
use Tarantool\Client\Exception\CommunicationFailed;
17
use Tarantool\Client\Exception\ConnectionFailed;
18
use Tarantool\Client\Exception\UnexpectedResponse;
19
use Tarantool\Client\Request\PingRequest;
20
use Tarantool\Client\Schema\Criteria;
21
use Tarantool\Client\Schema\Operations;
22
use Tarantool\Client\Tests\GreetingDataProvider;
23
use Tarantool\Client\Tests\Integration\ClientBuilder;
24
use Tarantool\Client\Tests\Integration\FakeServer\FakeServerBuilder;
25
use Tarantool\Client\Tests\Integration\FakeServer\Handler\AtConnectionHandler;
26
use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler;
27
use Tarantool\Client\Tests\Integration\TestCase;
28
29
final class ConnectionTest extends TestCase
30
{
31
    /**
32
     * @dataProvider provideAutoConnectData
33
     * @doesNotPerformAssertions
34
     *
35
     * @lua create_space('test_auto_connect'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}})
36
     */
37
    public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void
38
    {
39
        $object = $space ? $this->client->getSpace($space) : $this->client;
40
        $this->client->getHandler()->getConnection()->close();
41
42
        $object->$methodName(...$methodArgs);
43
    }
44
45
    public function provideAutoConnectData() : iterable
46
    {
47
        return [
48
            ['ping', []],
49
            ['call', ['box.stat']],
50
            ['evaluate', ['return 1']],
51
52
            ['select', [Criteria::key([42])], 'test_auto_connect'],
53
            ['insert', [[time()]], 'test_auto_connect'],
54
            ['replace', [[1, 2]], 'test_auto_connect'],
55
            ['update', [[1], Operations::add(1, 2)], 'test_auto_connect'],
56
            ['delete', [[1]], 'test_auto_connect'],
57
        ];
58
    }
59
60
    public function testMultipleConnect() : void
61
    {
62
        $conn = $this->client->getHandler()->getConnection();
63
64
        self::assertTrue($conn->isClosed());
65
66
        $conn->open();
67
        self::assertFalse($conn->isClosed());
68
69
        $conn->open();
70
        self::assertFalse($conn->isClosed());
71
    }
72
73
    public function tesMultipleDisconnect() : void
74
    {
75
        $conn = $this->client->getHandler()->getConnection();
76
77
        $conn->open();
78
        self::assertFalse($conn->isClosed());
79
80
        $conn->close();
81
        self::assertTrue($conn->isClosed());
82
83
        $conn->close();
84
        self::assertTrue($conn->isClosed());
85
    }
86
87
    public function testReturnSameGreeting() : void
88
    {
89
        $conn = $this->client->getHandler()->getConnection();
90
91
        $greeting1 = $conn->open();
92
        $greeting2 = $conn->open();
93
94
        self::assertSame($greeting1, $greeting2);
95
    }
96
97
    public function testReturnNewGreeting() : void
98
    {
99
        $conn = $this->client->getHandler()->getConnection();
100
101
        $greeting1 = $conn->open();
102
        $conn->close();
103
        $greeting2 = $conn->open();
104
105
        self::assertNotSame($greeting1, $greeting2);
106
    }
107
108
    public function testConnectInvalidHost() : void
109
    {
110
        $builder = ClientBuilder::createFromEnv()
111
            ->setHost('invalid_host');
112
113
        if (!$builder->isTcpConnection()) {
114
            self::markTestSkipped(sprintf('For the tcp connections only (current: "%s")', $builder->getUri()));
115
        }
116
117
        $client = $builder->build();
118
119
        $this->expectException(ConnectionFailed::class);
120
        $client->ping();
121
    }
122
123
    public function testConnectInvalidPort() : void
124
    {
125
        $builder = ClientBuilder::createFromEnv()
126
            ->setPort(123456);
127
128
        if (!$builder->isTcpConnection()) {
129
            self::markTestSkipped(sprintf('For the tcp connections only (current: "%s")', $builder->getUri()));
130
        }
131
132
        $client = $builder->build();
133
134
        $this->expectException(ConnectionFailed::class);
135
        $client->ping();
136
    }
137
138
    public function testConnectTimedOut() : void
139
    {
140
        $builder = ClientBuilder::createFromEnv();
141
        if (!$builder->isTcpConnection()) {
142
            self::markTestSkipped(sprintf('For tcp connections only (current: "%s")', $builder->getUri()));
143
        }
144
145
        // @see http://stackoverflow.com/q/100841/1160901
146
        $host = '8.8.8.8';
147
        $connectTimeout = 2;
148
149
        $client = $builder->setConnectionOptions(['connect_timeout' => $connectTimeout])
150
            ->setHost($host)
151
            ->setPort(8008)
152
            ->build();
153
154
        $start = microtime(true);
155
156
        try {
157
            $client->ping();
158
        } catch (ConnectionFailed $e) {
159
            if (false !== strpos($e->getMessage(), 'No route to host')) {
160
                self::markTestSkipped(sprintf('Unable to route to host %s', $host));
161
            }
162
163
            $time = microtime(true) - $start;
164
            self::assertRegExp('/Failed to connect to .+?: (Connection|Operation) timed out/', $e->getMessage());
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertRegExp() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/4086

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
165
            self::assertGreaterThanOrEqual($connectTimeout, $time);
166
            self::assertLessThanOrEqual($connectTimeout + 0.1, $time);
167
168
            return;
169
        }
170
171
        self::fail();
172
    }
173
174
    public function testUnexpectedResponse() : void
175
    {
176
        $client = ClientBuilder::createFromEnv()->build();
177
        $connection = self::triggerUnexpectedResponse($client->getHandler(), new PingRequest());
178
179
        // Tarantool will answer with the ping response
180
        try {
181
            $client->evaluate('return 42');
182
        } catch (UnexpectedResponse $e) {
183
            self::assertTrue($connection->isClosed());
184
185
            return;
186
        }
187
188
        self::fail(UnexpectedResponse::class.' was not thrown');
189
    }
190
191
    public function testOpenConnectionHandlesTheMissingGreetingCorrectly() : void
192
    {
193
        $clientBuilder = ClientBuilder::createFromEnvForTheFakeServer();
194
195
        FakeServerBuilder::create(
196
            new AtConnectionHandler(1, new WriteHandler('')),
197
            new AtConnectionHandler(2, new WriteHandler(GreetingDataProvider::generateGreeting()))
198
        )
199
            ->setUri($clientBuilder->getUri())
200
            ->start();
201
202
        $client = $clientBuilder->build();
203
        $connection = $client->getHandler()->getConnection();
204
205
        try {
206
            $connection->open();
207
            self::fail('Connection not established');
208
        } catch (CommunicationFailed $e) {
209
            self::assertSame('Unable to read greeting', $e->getMessage());
210
            // at that point the connection was successfully established,
211
            // but the greeting message was not read
212
        }
213
214
        // the second call should correctly handle
215
        // the missing greeting from the previous call
216
        $connection->open();
217
    }
218
}
219