Completed
Push — master ( afc89b...10bad0 )
by Eugene
05:20
created

ConnectionTest::tesMultipleDisconnect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 13
rs 9.8333
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
        $connectTimeout = 2;
141
        $builder = ClientBuilder::createFromEnv();
142
143
        // http://stackoverflow.com/q/100841/1160901
144
        $builder->setHost($host = '10.255.255.1');
145
        $builder->setConnectionOptions(['connect_timeout' => $connectTimeout]);
146
147
        if (!$builder->isTcpConnection()) {
148
            self::markTestSkipped(sprintf('For the tcp connections only (current: "%s")', $builder->getUri()));
149
        }
150
151
        $client = $builder->build();
152
153
        $start = microtime(true);
154
155
        try {
156
            $client->ping();
157
        } catch (ConnectionFailed $e) {
158
            if (false !== strpos($e->getMessage(), 'No route to host')) {
159
                self::markTestSkipped(sprintf('Unable to route to host %s', $host));
160
            }
161
162
            $time = microtime(true) - $start;
163
            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...
164
            self::assertGreaterThanOrEqual($connectTimeout, $time);
165
            self::assertLessThanOrEqual($connectTimeout + 0.1, $time);
166
167
            return;
168
        }
169
170
        self::fail();
171
    }
172
173
    public function testUnexpectedResponse() : void
174
    {
175
        $client = ClientBuilder::createFromEnv()->build();
176
        $connection = self::triggerUnexpectedResponse($client->getHandler(), new PingRequest());
177
178
        // Tarantool will answer with the ping response
179
        try {
180
            $client->evaluate('return 42');
181
        } catch (UnexpectedResponse $e) {
182
            self::assertTrue($connection->isClosed());
183
184
            return;
185
        }
186
187
        self::fail(UnexpectedResponse::class.' was not thrown');
188
    }
189
190
    public function testOpenConnectionHandlesTheMissingGreetingCorrectly() : void
191
    {
192
        $clientBuilder = ClientBuilder::createFromEnvForTheFakeServer();
193
194
        FakeServerBuilder::create(
195
            new AtConnectionHandler(1, new WriteHandler('')),
196
            new AtConnectionHandler(2, new WriteHandler(GreetingDataProvider::generateGreeting()))
197
        )
198
            ->setUri($clientBuilder->getUri())
199
            ->start();
200
201
        $client = $clientBuilder->build();
202
        $connection = $client->getHandler()->getConnection();
203
204
        try {
205
            $connection->open();
206
            self::fail('Connection not established');
207
        } catch (CommunicationFailed $e) {
208
            self::assertSame('Unable to read greeting', $e->getMessage());
209
            // at that point the connection was successfully established,
210
            // but the greeting message was not read
211
        }
212
213
        // the second call should correctly handle
214
        // the missing greeting from the previous call
215
        $connection->open();
216
    }
217
}
218