• 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 PersistentListTest 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 testInitHelper()
55  {
56      // PersistentList is not empty at the beginning of the tests
57      // because phpunit will cache the channels created by other test
58      // files.
59  }
60
61
62  public function testChannelNotPersist()
63  {
64      $this->channel1 = new Grpc\Channel('localhost:1', ['force_new' => true]);
65      $channel1_info = $this->channel1->getChannelInfo();
66      $plist_info = $this->channel1->getPersistentList();
67      $this->assertEquals($channel1_info['target'], 'localhost:1');
68      $this->assertEquals($channel1_info['ref_count'], 1);
69      $this->assertEquals($channel1_info['connectivity_status'],
70          GRPC\CHANNEL_IDLE);
71      $this->assertEquals(count($plist_info), 0);
72      $this->channel1->close();
73  }
74
75  public function testPersistentChannelCreateOneChannel()
76  {
77      $this->channel1 = new Grpc\Channel('localhost:1', []);
78      $channel1_info = $this->channel1->getChannelInfo();
79      $plist_info = $this->channel1->getPersistentList();
80      $this->assertEquals($channel1_info['target'], 'localhost:1');
81      $this->assertEquals($channel1_info['ref_count'], 2);
82      $this->assertEquals($channel1_info['connectivity_status'],
83                          GRPC\CHANNEL_IDLE);
84      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
85      $this->assertEquals(count($plist_info), 1);
86      $this->channel1->close();
87  }
88
89  public function testPersistentChannelCreateMultipleChannels()
90  {
91      $this->channel1 = new Grpc\Channel('localhost:1', []);
92      $plist_info = $this->channel1->getPersistentList();
93      $this->assertEquals(count($plist_info), 1);
94
95      $this->channel2 = new Grpc\Channel('localhost:2', []);
96      $plist_info = $this->channel1->getPersistentList();
97      $this->assertEquals(count($plist_info), 2);
98
99      $this->channel3 = new Grpc\Channel('localhost:3', []);
100      $plist_info = $this->channel1->getPersistentList();
101      $this->assertEquals(count($plist_info), 3);
102  }
103
104  public function testPersistentChannelStatusChange()
105  {
106      $this->channel1 = new Grpc\Channel('localhost:4', []);
107      $channel1_info = $this->channel1->getChannelInfo();
108      $this->assertEquals($channel1_info['connectivity_status'],
109                          GRPC\CHANNEL_IDLE);
110
111      $this->channel1->getConnectivityState(true);
112      $this->waitUntilNotIdle($this->channel1);
113      $channel1_info = $this->channel1->getChannelInfo();
114      $this->assertConnecting($channel1_info['connectivity_status']);
115      $this->channel1->close();
116  }
117
118  public function testPersistentChannelCloseChannel()
119  {
120      $this->channel1 = new Grpc\Channel('localhost:1', []);
121      $this->channel2 = new Grpc\Channel('localhost:1', []);
122
123      $channel1_info = $this->channel1->getChannelInfo();
124      $this->assertEquals($channel1_info['ref_count'], 3);
125      $plist_info = $this->channel1->getPersistentList();
126      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 3);
127
128      $this->channel1->close();
129      $plist_info = $this->channel1->getPersistentList();
130      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2);
131
132      $this->channel2->close();
133      $plist_info = $this->channel1->getPersistentList();
134      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 1);
135  }
136
137  public function testPersistentChannelSameTarget()
138  {
139      $this->channel1 = new Grpc\Channel('localhost:1', []);
140      $this->channel2 = new Grpc\Channel('localhost:1', []);
141      $plist = $this->channel2->getPersistentList();
142      $channel1_info = $this->channel1->getChannelInfo();
143      $channel2_info = $this->channel2->getChannelInfo();
144      // $channel1 and $channel2 shares the same channel, thus only 1
145      // channel should be in the persistent list.
146      $this->assertEquals($channel1_info['key'], $channel2_info['key']);
147      $this->assertArrayHasKey($channel1_info['key'], $plist);
148      $this->assertEquals(count($plist), 1);
149      $this->channel1->close();
150      $this->channel2->close();
151  }
152
153  public function testPersistentChannelDifferentTarget()
154  {
155      $this->channel1 = new Grpc\Channel('localhost:1', []);
156      $channel1_info = $this->channel1->getChannelInfo();
157      $this->channel2 = new Grpc\Channel('localhost:2', []);
158      $channel2_info = $this->channel1->getChannelInfo();
159      $plist_info = $this->channel1->getPersistentList();
160      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
161      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
162      $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2);
163      $this->assertEquals($plist_info[$channel2_info['key']]['ref_count'], 2);
164      $plist_info = $this->channel1->getPersistentList();
165      $this->assertEquals(count($plist_info), 2);
166      $this->channel1->close();
167      $this->channel2->close();
168  }
169
170  public function testPersistentChannelSharedChannelClose()
171  {
172    $this->expectException(\RuntimeException::class);
173    $this->expectExceptionMessage("startBatch Error. Channel is closed");
174    // same underlying channel
175      $this->channel1 = new Grpc\Channel('localhost:10001', [
176          "grpc_target_persist_bound" => 2,
177      ]);
178      $this->channel2 = new Grpc\Channel('localhost:10001', []);
179      $this->server = new Grpc\Server([]);
180      $this->port = $this->server->addHttp2Port('localhost:10001');
181      $this->server->start();
182
183      // channel2 can still be use
184      $state = $this->channel2->getConnectivityState();
185      $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
186
187      $call1 = new Grpc\Call($this->channel1,
188          '/foo',
189          Grpc\Timeval::infFuture());
190      $call2 = new Grpc\Call($this->channel2,
191          '/foo',
192          Grpc\Timeval::infFuture());
193      $call3 = new Grpc\Call($this->channel1,
194          '/foo',
195          Grpc\Timeval::infFuture());
196      $call4 = new Grpc\Call($this->channel2,
197          '/foo',
198          Grpc\Timeval::infFuture());
199      $batch = [
200          Grpc\OP_SEND_INITIAL_METADATA => [],
201      ];
202
203      $result = $call1->startBatch($batch);
204      $this->assertTrue($result->send_metadata);
205      $result = $call2->startBatch($batch);
206      $this->assertTrue($result->send_metadata);
207
208      $this->channel1->close();
209      // After closing channel1, channel2 can still be use
210      $result = $call4->startBatch($batch);
211      $this->assertTrue($result->send_metadata);
212      // channel 1 is closed, it will throw an exception.
213      $result = $call3->startBatch($batch);
214  }
215
216  public function testPersistentChannelTargetDefaultUpperBound()
217  {
218      $this->channel1 = new Grpc\Channel('localhost:10002', []);
219      $channel1_info = $this->channel1->getChannelInfo();
220      $this->assertEquals($channel1_info['target_upper_bound'], 1);
221      $this->assertEquals($channel1_info['target_current_size'], 1);
222  }
223
224  public function testPersistentChannelTargetUpperBoundZero()
225  {
226      $this->channel1 = new Grpc\Channel('localhost:10002', [
227          "grpc_target_persist_bound" => 0,
228      ]);
229      // channel1 will not be persisted.
230      $channel1_info = $this->channel1->getChannelInfo();
231      $this->assertEquals($channel1_info['target_upper_bound'], 0);
232      $this->assertEquals($channel1_info['target_current_size'], 0);
233      $plist_info = $this->channel1->getPersistentList();
234      $this->assertEquals(0, count($plist_info));
235  }
236
237  public function testPersistentChannelTargetUpperBoundNotZero()
238  {
239      $this->channel1 = new Grpc\Channel('localhost:10003', [
240          "grpc_target_persist_bound" => 3,
241      ]);
242      $channel1_info = $this->channel1->getChannelInfo();
243      $this->assertEquals($channel1_info['target_upper_bound'], 3);
244      $this->assertEquals($channel1_info['target_current_size'], 1);
245
246      // The upper bound should not be changed
247      $this->channel2 = new Grpc\Channel('localhost:10003', []);
248      $channel2_info = $this->channel2->getChannelInfo();
249      $this->assertEquals($channel2_info['target_upper_bound'], 3);
250      $this->assertEquals($channel2_info['target_current_size'], 1);
251
252      // The upper bound should not be changed
253      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
254          null);
255      $this->channel3 = new Grpc\Channel('localhost:10003',
256          ['credentials' => $channel_credentials]);
257      $channel3_info = $this->channel3->getChannelInfo();
258      $this->assertEquals($channel3_info['target_upper_bound'], 3);
259      $this->assertEquals($channel3_info['target_current_size'], 2);
260
261      // The upper bound should not be changed
262      $this->channel4 = new Grpc\Channel('localhost:10003', [
263          "grpc_target_persist_bound" => 5,
264      ]);
265      $channel4_info = $this->channel4->getChannelInfo();
266      $this->assertEquals($channel4_info['target_upper_bound'], 5);
267      $this->assertEquals($channel4_info['target_current_size'], 2);
268  }
269
270  public function testPersistentChannelDefaultOutBound1()
271  {
272      $this->channel1 = new Grpc\Channel('localhost:10004', []);
273      // Make channel1 not IDLE.
274      $this->channel1->getConnectivityState(true);
275      $this->waitUntilNotIdle($this->channel1);
276      $channel1_info = $this->channel1->getChannelInfo();
277      $this->assertConnecting($channel1_info['connectivity_status']);
278
279      // Since channel1 is CONNECTING, channel 2 will not be persisted
280      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
281        null);
282      $this->channel2 = new Grpc\Channel('localhost:10004',
283          ['credentials' => $channel_credentials]);
284      $channel2_info = $this->channel2->getChannelInfo();
285      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
286
287      // By default, target 'localhost:10011' only persist one channel.
288      // Since channel1 is not Idle channel2 will not be persisted.
289      $plist_info = $this->channel1->getPersistentList();
290      $this->assertEquals(1, count($plist_info));
291      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
292      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
293  }
294
295  public function testPersistentChannelDefaultOutBound2()
296  {
297      $this->channel1 = new Grpc\Channel('localhost:10005', []);
298      $channel1_info = $this->channel1->getChannelInfo();
299      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
300
301      // Although channel1 is IDLE, channel1 still has reference to the underline
302      // gRPC channel. channel2 will not be persisted
303      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
304        null);
305      $this->channel2 = new Grpc\Channel('localhost:10005',
306          ['credentials' => $channel_credentials]);
307      $channel2_info = $this->channel2->getChannelInfo();
308      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
309
310      // By default, target 'localhost:10011' only persist one channel.
311      // Since channel1 Idle, channel2 will be persisted.
312      $plist_info = $this->channel1->getPersistentList();
313      $this->assertEquals(1, count($plist_info));
314      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
315      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
316  }
317
318  public function testPersistentChannelDefaultOutBound3()
319  {
320      $this->channel1 = new Grpc\Channel('localhost:10006', []);
321      $channel1_info = $this->channel1->getChannelInfo();
322      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
323
324      $this->channel1->close();
325      // channel1 is closed, no reference holds to the underline channel.
326      // channel2 can be persisted.
327      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
328        null);
329      $this->channel2 = new Grpc\Channel('localhost:10006',
330        ['credentials' => $channel_credentials]);
331      $channel2_info = $this->channel2->getChannelInfo();
332      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
333
334      // By default, target 'localhost:10011' only persist one channel.
335      // Since channel1 Idle, channel2 will be persisted.
336      $plist_info = $this->channel2->getPersistentList();
337      $this->assertEquals(1, count($plist_info));
338      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
339      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
340  }
341
342  public function testPersistentChannelTwoUpperBound()
343  {
344      $this->channel1 = new Grpc\Channel('localhost:10007', [
345          "grpc_target_persist_bound" => 2,
346      ]);
347      $channel1_info = $this->channel1->getChannelInfo();
348      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']);
349
350      // Since channel1 is IDLE, channel 1 will be deleted
351      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
352          null);
353      $this->channel2 = new Grpc\Channel('localhost:10007',
354          ['credentials' => $channel_credentials]);
355      $channel2_info = $this->channel2->getChannelInfo();
356      $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']);
357
358      $plist_info = $this->channel1->getPersistentList();
359      $this->assertEquals(2, count($plist_info));
360      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
361      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
362  }
363
364  public function testPersistentChannelTwoUpperBoundOutBound1()
365  {
366      $this->channel1 = new Grpc\Channel('localhost:10011', [
367          "grpc_target_persist_bound" => 2,
368      ]);
369      $channel1_info = $this->channel1->getChannelInfo();
370
371      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
372        null);
373      $this->channel2 = new Grpc\Channel('localhost:10011',
374          ['credentials' => $channel_credentials]);
375      $channel2_info = $this->channel2->getChannelInfo();
376
377      // Close channel1, so that new channel can be persisted.
378      $this->channel1->close();
379
380      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
381        null);
382      $this->channel3 = new Grpc\Channel('localhost:10011',
383          ['credentials' => $channel_credentials]);
384      $channel3_info = $this->channel3->getChannelInfo();
385
386      $plist_info = $this->channel1->getPersistentList();
387      $this->assertEquals(2, count($plist_info));
388      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
389      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
390      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
391  }
392
393  public function testPersistentChannelTwoUpperBoundOutBound2()
394  {
395      $this->channel1 = new Grpc\Channel('localhost:10012', [
396          "grpc_target_persist_bound" => 2,
397      ]);
398      $channel1_info = $this->channel1->getChannelInfo();
399
400      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
401        null);
402      $this->channel2 = new Grpc\Channel('localhost:10012',
403        ['credentials' => $channel_credentials]);
404      $channel2_info = $this->channel2->getChannelInfo();
405
406      // Close channel2, so that new channel can be persisted.
407      $this->channel2->close();
408
409      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
410        null);
411      $this->channel3 = new Grpc\Channel('localhost:10012',
412        ['credentials' => $channel_credentials]);
413      $channel3_info = $this->channel3->getChannelInfo();
414
415      $plist_info = $this->channel1->getPersistentList();
416      $this->assertEquals(2, count($plist_info));
417      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
418      $this->assertArrayNotHasKey($channel2_info['key'], $plist_info);
419      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
420  }
421
422  public function testPersistentChannelTwoUpperBoundOutBound3()
423  {
424      $this->channel1 = new Grpc\Channel('localhost:10013', [
425          "grpc_target_persist_bound" => 2,
426      ]);
427      $channel1_info = $this->channel1->getChannelInfo();
428
429      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
430          null);
431      $this->channel2 = new Grpc\Channel('localhost:10013',
432          ['credentials' => $channel_credentials]);
433      $this->channel2->getConnectivityState(true);
434      $this->waitUntilNotIdle($this->channel2);
435      $channel2_info = $this->channel2->getChannelInfo();
436      $this->assertConnecting($channel2_info['connectivity_status']);
437
438      // Only one channel will be deleted
439      $this->channel1->close();
440      $this->channel2->close();
441
442      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
443        null);
444      $this->channel3 = new Grpc\Channel('localhost:10013',
445          ['credentials' => $channel_credentials]);
446      $channel3_info = $this->channel3->getChannelInfo();
447
448      // Only the Idle Channel will be deleted
449      $plist_info = $this->channel1->getPersistentList();
450      $this->assertEquals(2, count($plist_info));
451      $this->assertArrayNotHasKey($channel1_info['key'], $plist_info);
452      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
453      $this->assertArrayHasKey($channel3_info['key'], $plist_info);
454  }
455
456  public function testPersistentChannelTwoUpperBoundOutBound4()
457  {
458      $this->channel1 = new Grpc\Channel('localhost:10014', [
459          "grpc_target_persist_bound" => 2,
460      ]);
461      $this->channel1->getConnectivityState(true);
462      $this->waitUntilNotIdle($this->channel1);
463      $channel1_info = $this->channel1->getChannelInfo();
464      $this->assertConnecting($channel1_info['connectivity_status']);
465
466      $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null,
467          null);
468      $this->channel2 = new Grpc\Channel('localhost:10014',
469          ['credentials' => $channel_credentials]);
470      $this->channel2->getConnectivityState(true);
471      $this->waitUntilNotIdle($this->channel2);
472      $channel2_info = $this->channel2->getChannelInfo();
473      $this->assertConnecting($channel2_info['connectivity_status']);
474
475      $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null,
476          null);
477      $this->channel3 = new Grpc\Channel('localhost:10014',
478          ['credentials' => $channel_credentials]);
479      $channel3_info = $this->channel3->getChannelInfo();
480
481      // Channel3 will not be persisted
482      $plist_info = $this->channel1->getPersistentList();
483      $this->assertEquals(2, count($plist_info));
484      $this->assertArrayHasKey($channel1_info['key'], $plist_info);
485      $this->assertArrayHasKey($channel2_info['key'], $plist_info);
486      $this->assertArrayNotHasKey($channel3_info['key'], $plist_info);
487  }
488}
489