• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?php
2/*
3 *
4 * Copyright 2015 gRPC authors.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20/**
21 * @group persistent_list_bound_tests
22 */
23class PersistentChannelTest extends \PHPUnit\Framework\TestCase
24{
25  public function setUp(): void
26  {
27  }
28
29  public function tearDown(): void
30  {
31    $channel_clean_persistent =
32        new Grpc\Channel('localhost:50010', []);
33    $plist = $channel_clean_persistent->getPersistentList();
34    $channel_clean_persistent->cleanPersistentList();
35  }
36
37  public function waitUntilNotIdle($channel) {
38      for ($i = 0; $i < 10; $i++) {
39          $now = Grpc\Timeval::now();
40          $deadline = $now->add(new Grpc\Timeval(1000));
41          if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
42              $deadline)) {
43              return true;
44          }
45      }
46      $this->assertTrue(false);
47  }
48
49  public function assertConnecting($state) {
50      $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
51      $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
52  }
53
54  public function testChannelNotPersist()
55  {
56      $this->channel1 = new Grpc\Channel('localhost:1', ['force_new' => true]);
57      $channel1_info = $this->channel1->getChannelInfo();
58      $plist_info = $this->channel1->getPersistentList();
59      $this->assertEquals($channel1_info['target'], 'localhost:1');
60      $this->assertEquals($channel1_info['ref_count'], 1);
61      $this->assertEquals($channel1_info['connectivity_status'],
62          GRPC\CHANNEL_IDLE);
63      $this->assertEquals(count($plist_info), 0);
64      $this->channel1->close();
65  }
66
67  public function testPersistentChannelCreateOneChannel()
68  {
69      $this->channel1 = new Grpc\Channel('localhost:1', []);
70      $channel1_info = $this->channel1->getChannelInfo();
71      $plist_info = $this->channel1->getPersistentList();
72      $this->assertEquals($channel1_info['target'], 'localhost:1');
73      $this->assertEquals($channel1_info['ref_count'], 2);
74      $this->assertEquals($channel1_info['connectivity_status'],
75                          GRPC\CHANNEL_IDLE);
76      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
77      $this->assertEquals(count($plist_info), 1);
78      $this->channel1->close();
79  }
80
81  public function testPersistentChannelCreateMultipleChannels()
82  {
83      $this->channel1 = new Grpc\Channel('localhost:1', []);
84      $plist_info = $this->channel1->getPersistentList();
85      $this->assertEquals(count($plist_info), 1);
86
87      $this->channel2 = new Grpc\Channel('localhost:2', []);
88      $plist_info = $this->channel1->getPersistentList();
89      $this->assertEquals(count($plist_info), 2);
90
91      $this->channel3 = new Grpc\Channel('localhost:3', []);
92      $plist_info = $this->channel1->getPersistentList();
93      $this->assertEquals(count($plist_info), 3);
94  }
95
96  public function testPersistentChannelStatusChange()
97  {
98      $this->channel1 = new Grpc\Channel('localhost:4', []);
99      $channel1_info = $this->channel1->getChannelInfo();
100      $this->assertEquals($channel1_info['connectivity_status'],
101                          GRPC\CHANNEL_IDLE);
102
103      $this->channel1->getConnectivityState(true);
104      $this->waitUntilNotIdle($this->channel1);
105      $channel1_info = $this->channel1->getChannelInfo();
106      $this->assertConnecting($channel1_info['connectivity_status']);
107      $this->channel1->close();
108  }
109
110  public function testPersistentChannelCloseChannel()
111  {
112      $this->channel1 = new Grpc\Channel('localhost:1', []);
113      $this->channel2 = new Grpc\Channel('localhost:1', []);
114
115      $channel1_info = $this->channel1->getChannelInfo();
116      $this->assertEquals($channel1_info['ref_count'], 3);
117      $plist_info = $this->channel1->getPersistentList();
118      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 3);
119
120      $this->channel1->close();
121      $plist_info = $this->channel1->getPersistentList();
122      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2);
123
124      $this->channel2->close();
125      $plist_info = $this->channel1->getPersistentList();
126      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 1);
127  }
128
129  public function testPersistentChannelSameTarget()
130  {
131      $this->channel1 = new Grpc\Channel('localhost:1', []);
132      $this->channel2 = new Grpc\Channel('localhost:1', []);
133      $plist = $this->channel2->getPersistentList();
134      $channel1_info = $this->channel1->getChannelInfo();
135      $channel2_info = $this->channel2->getChannelInfo();
136      // $channel1 and $channel2 shares the same channel, thus only 1
137      // channel should be in the persistent list.
138      $this->assertEquals($channel1_info['key'], $channel2_info['key']);
139      $this->assertArrayHasKey($channel1_info['key'], $plist);
140      $this->assertEquals(count($plist), 1);
141      $this->channel1->close();
142      $this->channel2->close();
143  }
144
145  public function testPersistentChannelDifferentTarget()
146  {
147      $this->channel1 = new Grpc\Channel('localhost:1', []);
148      $channel1_info = $this->channel1->getChannelInfo();
149      $this->channel2 = new Grpc\Channel('localhost:2', []);
150      $channel2_info = $this->channel1->getChannelInfo();
151      $plist_info = $this->channel1->getPersistentList();
152      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
153      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
154      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2);
155      $this->assertEquals($plist_info[$channel2_info['key']]['ref_count'], 2);
156      $plist_info = $this->channel1->getPersistentList();
157      $this->assertEquals(count($plist_info), 2);
158      $this->channel1->close();
159      $this->channel2->close();
160  }
161
162  public function testPersistentChannelSharedChannelClose()
163  {
164    $this->expectException(\RuntimeException::class);
165    $this->expectExceptionMessage("startBatch Error. Channel is closed");
166    // same underlying channel
167      $this->channel1 = new Grpc\Channel('localhost:10001', [
168          "grpc_target_persist_bound" => 2,
169      ]);
170      $this->channel2 = new Grpc\Channel('localhost:10001', []);
171      $this->server = new Grpc\Server([]);
172      $this->port = $this->server->addHttp2Port('localhost:10001');
173      $this->server->start();
174
175      // channel2 can still be use
176      $state = $this->channel2->getConnectivityState();
177      $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
178
179      $call1 = new Grpc\Call($this->channel1,
180          '/foo',
181          Grpc\Timeval::infFuture());
182      $call2 = new Grpc\Call($this->channel2,
183          '/foo',
184          Grpc\Timeval::infFuture());
185      $call3 = new Grpc\Call($this->channel1,
186          '/foo',
187          Grpc\Timeval::infFuture());
188      $call4 = new Grpc\Call($this->channel2,
189          '/foo',
190          Grpc\Timeval::infFuture());
191      $batch = [
192          Grpc\OP_SEND_INITIAL_METADATA => [],
193      ];
194
195      $result = $call1->startBatch($batch);
196      $this->assertTrue($result->send_metadata);
197      $result = $call2->startBatch($batch);
198      $this->assertTrue($result->send_metadata);
199
200      $this->channel1->close();
201      // After closing channel1, channel2 can still be use
202      $result = $call4->startBatch($batch);
203      $this->assertTrue($result->send_metadata);
204      // channel 1 is closed, it will throw an exception.
205      $result = $call3->startBatch($batch);
206  }
207
208  public function testPersistentChannelTargetDefaultUpperBound()
209  {
210      $this->channel1 = new Grpc\Channel('localhost:10002', []);
211      $channel1_info = $this->channel1->getChannelInfo();
212      $this->assertEquals($channel1_info['target_upper_bound'], 1);
213      $this->assertEquals($channel1_info['target_current_size'], 1);
214  }
215
216  public function testPersistentChannelTargetUpperBoundZero()
217  {
218      $this->channel1 = new Grpc\Channel('localhost:10002', [
219          "grpc_target_persist_bound" => 0,
220      ]);
221      // channel1 will not be persisted.
222      $channel1_info = $this->channel1->getChannelInfo();
223      $this->assertEquals($channel1_info['target_upper_bound'], 0);
224      $this->assertEquals($channel1_info['target_current_size'], 0);
225      $plist_info = $this->channel1->getPersistentList();
226      $this->assertEquals(0, count($plist_info));
227  }
228
229  public function testPersistentChannelTargetUpperBoundNotZero()
230  {
231      $this->channel1 = new Grpc\Channel('localhost:10003', [
232          "grpc_target_persist_bound" => 3,
233      ]);
234      $channel1_info = $this->channel1->getChannelInfo();
235      $this->assertEquals($channel1_info['target_upper_bound'], 3);
236      $this->assertEquals($channel1_info['target_current_size'], 1);
237
238      // The upper bound should not be changed
239      $this->channel2 = new Grpc\Channel('localhost:10003', []);
240      $channel2_info = $this->channel2->getChannelInfo();
241      $this->assertEquals($channel2_info['target_upper_bound'], 3);
242      $this->assertEquals($channel2_info['target_current_size'], 1);
243
244      // The upper bound should not be changed
245      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
246          null);
247      $this->channel3 = new Grpc\Channel('localhost:10003',
248          ['credentials' => $channel_credentials]);
249      $channel3_info = $this->channel3->getChannelInfo();
250      $this->assertEquals($channel3_info['target_upper_bound'], 3);
251      $this->assertEquals($channel3_info['target_current_size'], 2);
252
253      // The upper bound should not be changed
254      $this->channel4 = new Grpc\Channel('localhost:10003', [
255          "grpc_target_persist_bound" => 5,
256      ]);
257      $channel4_info = $this->channel4->getChannelInfo();
258      $this->assertEquals($channel4_info['target_upper_bound'], 5);
259      $this->assertEquals($channel4_info['target_current_size'], 2);
260  }
261
262  public function testPersistentChannelDefaultOutBound1()
263  {
264      $this->channel1 = new Grpc\Channel('localhost:10004', []);
265      // Make channel1 not IDLE.
266      $this->channel1->getConnectivityState(true);
267      $this->waitUntilNotIdle($this->channel1);
268      $channel1_info = $this->channel1->getChannelInfo();
269      $this->assertConnecting($channel1_info['connectivity_status']);
270
271      // Since channel1 is CONNECTING, channel 2 will not be persisted
272      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
273        null);
274      $this->channel2 = new Grpc\Channel('localhost:10004',
275          ['credentials' => $channel_credentials]);
276      $channel2_info = $this->channel2->getChannelInfo();
277      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
278
279      // By default, target 'localhost:10011' only persist one channel.
280      // Since channel1 is not Idle channel2 will not be persisted.
281      $plist_info = $this->channel1->getPersistentList();
282      $this->assertEquals(1, count($plist_info));
283      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
284      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
285  }
286
287  public function testPersistentChannelDefaultOutBound2()
288  {
289      $this->channel1 = new Grpc\Channel('localhost:10005', []);
290      $channel1_info = $this->channel1->getChannelInfo();
291      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
292
293      // Although channel1 is IDLE, channel1 still has reference to the underline
294      // gRPC channel. channel2 will not be persisted
295      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
296        null);
297      $this->channel2 = new Grpc\Channel('localhost:10005',
298          ['credentials' => $channel_credentials]);
299      $channel2_info = $this->channel2->getChannelInfo();
300      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
301
302      // By default, target 'localhost:10011' only persist one channel.
303      // Since channel1 Idle, channel2 will be persisted.
304      $plist_info = $this->channel1->getPersistentList();
305      $this->assertEquals(1, count($plist_info));
306      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
307      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
308  }
309
310  public function testPersistentChannelDefaultOutBound3()
311  {
312      $this->channel1 = new Grpc\Channel('localhost:10006', []);
313      $channel1_info = $this->channel1->getChannelInfo();
314      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
315
316      $this->channel1->close();
317      // channel1 is closed, no reference holds to the underline channel.
318      // channel2 can be persisted.
319      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
320        null);
321      $this->channel2 = new Grpc\Channel('localhost:10006',
322        ['credentials' => $channel_credentials]);
323      $channel2_info = $this->channel2->getChannelInfo();
324      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
325
326      // By default, target 'localhost:10011' only persist one channel.
327      // Since channel1 Idle, channel2 will be persisted.
328      $plist_info = $this->channel2->getPersistentList();
329      $this->assertEquals(1, count($plist_info));
330      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
331      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
332  }
333
334  public function testPersistentChannelTwoUpperBound()
335  {
336      $this->channel1 = new Grpc\Channel('localhost:10007', [
337          "grpc_target_persist_bound" => 2,
338      ]);
339      $channel1_info = $this->channel1->getChannelInfo();
340      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
341
342      // Since channel1 is IDLE, channel 1 will be deleted
343      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
344          null);
345      $this->channel2 = new Grpc\Channel('localhost:10007',
346          ['credentials' => $channel_credentials]);
347      $channel2_info = $this->channel2->getChannelInfo();
348      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
349
350      $plist_info = $this->channel1->getPersistentList();
351      $this->assertEquals(2, count($plist_info));
352      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
353      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
354  }
355
356  public function testPersistentChannelTwoUpperBoundOutBound1()
357  {
358      $this->channel1 = new Grpc\Channel('localhost:10011', [
359          "grpc_target_persist_bound" => 2,
360      ]);
361      $channel1_info = $this->channel1->getChannelInfo();
362
363      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
364        null);
365      $this->channel2 = new Grpc\Channel('localhost:10011',
366          ['credentials' => $channel_credentials]);
367      $channel2_info = $this->channel2->getChannelInfo();
368
369      // Close channel1, so that new channel can be persisted.
370      $this->channel1->close();
371
372      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
373        null);
374      $this->channel3 = new Grpc\Channel('localhost:10011',
375          ['credentials' => $channel_credentials]);
376      $channel3_info = $this->channel3->getChannelInfo();
377
378      $plist_info = $this->channel1->getPersistentList();
379      $this->assertEquals(2, count($plist_info));
380      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
381      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
382      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
383  }
384
385  public function testPersistentChannelTwoUpperBoundOutBound2()
386  {
387      $this->channel1 = new Grpc\Channel('localhost:10012', [
388          "grpc_target_persist_bound" => 2,
389      ]);
390      $channel1_info = $this->channel1->getChannelInfo();
391
392      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
393        null);
394      $this->channel2 = new Grpc\Channel('localhost:10012',
395        ['credentials' => $channel_credentials]);
396      $channel2_info = $this->channel2->getChannelInfo();
397
398      // Close channel2, so that new channel can be persisted.
399      $this->channel2->close();
400
401      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
402        null);
403      $this->channel3 = new Grpc\Channel('localhost:10012',
404        ['credentials' => $channel_credentials]);
405      $channel3_info = $this->channel3->getChannelInfo();
406
407      $plist_info = $this->channel1->getPersistentList();
408      $this->assertEquals(2, count($plist_info));
409      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
410      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
411      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
412  }
413
414  public function testPersistentChannelTwoUpperBoundOutBound3()
415  {
416      $this->channel1 = new Grpc\Channel('localhost:10013', [
417          "grpc_target_persist_bound" => 2,
418      ]);
419      $channel1_info = $this->channel1->getChannelInfo();
420
421      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
422          null);
423      $this->channel2 = new Grpc\Channel('localhost:10013',
424          ['credentials' => $channel_credentials]);
425      $this->channel2->getConnectivityState(true);
426      $this->waitUntilNotIdle($this->channel2);
427      $channel2_info = $this->channel2->getChannelInfo();
428      $this->assertConnecting($channel2_info['connectivity_status']);
429
430      // Only one channel will be deleted
431      $this->channel1->close();
432      $this->channel2->close();
433
434      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
435        null);
436      $this->channel3 = new Grpc\Channel('localhost:10013',
437          ['credentials' => $channel_credentials]);
438      $channel3_info = $this->channel3->getChannelInfo();
439
440      // Only the Idle Channel will be deleted
441      $plist_info = $this->channel1->getPersistentList();
442      $this->assertEquals(2, count($plist_info));
443      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
444      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
445      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
446  }
447
448  public function testPersistentChannelTwoUpperBoundOutBound4()
449  {
450      $this->channel1 = new Grpc\Channel('localhost:10014', [
451          "grpc_target_persist_bound" => 2,
452      ]);
453      $this->channel1->getConnectivityState(true);
454      $this->waitUntilNotIdle($this->channel1);
455      $channel1_info = $this->channel1->getChannelInfo();
456      $this->assertConnecting($channel1_info['connectivity_status']);
457
458      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
459          null);
460      $this->channel2 = new Grpc\Channel('localhost:10014',
461          ['credentials' => $channel_credentials]);
462      $this->channel2->getConnectivityState(true);
463      $this->waitUntilNotIdle($this->channel2);
464      $channel2_info = $this->channel2->getChannelInfo();
465      $this->assertConnecting($channel2_info['connectivity_status']);
466
467      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
468          null);
469      $this->channel3 = new Grpc\Channel('localhost:10014',
470          ['credentials' => $channel_credentials]);
471      $channel3_info = $this->channel3->getChannelInfo();
472
473      // Channel3 will not be persisted
474      $plist_info = $this->channel1->getPersistentList();
475      $this->assertEquals(2, count($plist_info));
476      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
477      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
478      $this->assertArrayNotHasKey($channel3_info['key'], $plist_info);
479  }
480}
481