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()); |
|
|
|
|
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
|
|
|
|
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.