b7df853bb2d61e48e5729fec866fc59a8df4056b
[platform/upstream/grpc.git] / src / php / tests / unit_tests / ChannelTest.php
1 <?php
2 /*
3  *
4  * Copyright 2018 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 class ChannelTest extends \PHPUnit\Framework\TestCase
21 {
22     public function setUp(): void
23     {
24     }
25
26     public function tearDown(): void
27     {
28         if (!empty($this->channel)) {
29             $this->channel->close();
30         }
31     }
32
33     public function testInsecureCredentials()
34     {
35         $this->channel = new Grpc\Channel('localhost:50000',
36             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
37         $this->assertSame('Grpc\Channel', get_class($this->channel));
38     }
39
40     public function testConstructorCreateSsl()
41     {
42         $channel = new Grpc\Channel('localhost:50033', 
43             ['credentials' => \Grpc\ChannelCredentials::createSsl()]);
44         $this->assertNotNull($channel);
45     }
46
47     public function testCreateXdsWithSsl()
48     {
49         $xdsCreds = \Grpc\ChannelCredentials::createXds(
50             \Grpc\ChannelCredentials::createSsl()
51         );
52         $this->assertNotNull($xdsCreds);
53     }
54
55     public function disabled_testCreateXdsWithInsecure() {
56         $xdsCreds = \Grpc\ChannelCredentials::createXds(
57             \Grpc\ChannelCredentials::createInsecure()
58         );
59         $this->assertNotNull($xdsCreds);
60     }
61
62     public function testCreateXdsWithNull() {
63         $this->expectException(\InvalidArgumentException::class);
64         $xdsCreds = \Grpc\ChannelCredentials::createXds(null);
65     }
66
67     public function testCreateXdsWithInvalidType()
68     {
69         $expected = $this->logicalOr(
70             // PHP8
71             new \PHPUnit\Framework\Constraint\Exception(\InvalidArgumentException::class),
72             // PHP7
73             new \PHPUnit\Framework\Constraint\Exception(\TypeError::class)
74         );
75         try {
76             $xdsCreds = \Grpc\ChannelCredentials::createXds("invalid-type");
77         } catch (\Throwable $exception) {
78             $this->assertThat($exception, $expected);
79             return;
80         }
81         $this->assertThat(null, $expected);
82     }
83
84     public function testGetConnectivityState()
85     {
86         $this->channel = new Grpc\Channel('localhost:50001',
87              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
88         $state = $this->channel->getConnectivityState();
89         $this->assertEquals(0, $state);
90     }
91
92     public function testGetConnectivityStateWithInt()
93     {
94         $this->channel = new Grpc\Channel('localhost:50002',
95              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
96         $state = $this->channel->getConnectivityState(123);
97         $this->assertEquals(0, $state);
98     }
99
100     public function testGetConnectivityStateWithString()
101     {
102         $this->channel = new Grpc\Channel('localhost:50003',
103              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
104         $state = $this->channel->getConnectivityState('hello');
105         $this->assertEquals(0, $state);
106     }
107
108     public function testGetConnectivityStateWithBool()
109     {
110         $this->channel = new Grpc\Channel('localhost:50004',
111              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
112         $state = $this->channel->getConnectivityState(true);
113         $this->assertEquals(0, $state);
114     }
115
116     public function testGetTarget()
117     {
118         $this->channel = new Grpc\Channel('localhost:50005',
119              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
120         $target = $this->channel->getTarget();
121         $this->assertTrue(is_string($target));
122     }
123
124     public function testWatchConnectivityState()
125     {
126         $this->channel = new Grpc\Channel('localhost:50006',
127              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
128         $now = Grpc\Timeval::now();
129         $deadline = $now->add(new Grpc\Timeval(100*1000));  // 100ms
130         // we act as if 'CONNECTING'(=1) was the last state
131         // we saw, so the default state of 'IDLE' should be delivered instantly
132         $state = $this->channel->watchConnectivityState(1, $deadline);
133         $this->assertTrue($state);
134         unset($now);
135         unset($deadline);
136     }
137
138     public function testClose()
139     {
140         $this->channel = new Grpc\Channel('localhost:50007',
141              ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
142         $this->assertNotNull($this->channel);
143         $this->channel->close();
144     }
145
146     public function testInvalidConstructorWithNull()
147     {
148         $this->expectException(\InvalidArgumentException::class);
149         $this->channel = new Grpc\Channel();
150         $this->assertNull($this->channel);
151     }
152
153     public function testInvalidConstructorWith()
154     {
155         $this->expectException(\InvalidArgumentException::class);
156         $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
157         $this->assertNull($this->channel);
158     }
159
160     public function testInvalidCredentials()
161     {
162         $this->expectException(\InvalidArgumentException::class);
163         $this->channel = new Grpc\Channel('localhost:50009',
164             ['credentials' => new Grpc\Timeval(100)]);
165     }
166
167     public function testInvalidOptionsArray()
168     {
169         $this->expectException(\InvalidArgumentException::class);
170         $this->channel = new Grpc\Channel('localhost:50010',
171             ['abc' => []]);
172     }
173
174     public function testInvalidGetConnectivityStateWithArray()
175     {
176         $this->expectException(\InvalidArgumentException::class);
177         $this->channel = new Grpc\Channel('localhost:50011',
178             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
179         $this->channel->getConnectivityState([]);
180     }
181
182     public function testInvalidWatchConnectivityState()
183     {
184         $this->expectException(\InvalidArgumentException::class);
185         $this->channel = new Grpc\Channel('localhost:50012',
186             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
187         $this->channel->watchConnectivityState([]);
188     }
189
190     public function testInvalidWatchConnectivityState2()
191     {
192         $this->expectException(\InvalidArgumentException::class);
193         $this->channel = new Grpc\Channel('localhost:50013',
194             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
195         $this->channel->watchConnectivityState(1, 'hi');
196     }
197
198
199     public function assertConnecting($state) {
200       $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
201                         $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
202     }
203
204     public function waitUntilNotIdle($channel) {
205         for ($i = 0; $i < 10; $i++) {
206             $now = Grpc\Timeval::now();
207             $deadline = $now->add(new Grpc\Timeval(1000));
208             if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
209                                                  $deadline)) {
210                 return true;
211             }
212         }
213         $this->assertTrue(false);
214     }
215
216     public function testPersistentChannelSameHost()
217     {
218         $this->channel1 = new Grpc\Channel('localhost:50014', [
219             "grpc_target_persist_bound" => 3,
220         ]);
221         // the underlying grpc channel is the same by default
222         // when connecting to the same host
223         $this->channel2 = new Grpc\Channel('localhost:50014', []);
224
225         // both channels should be IDLE
226         $state = $this->channel1->getConnectivityState();
227         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
228         $state = $this->channel2->getConnectivityState();
229         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
230
231         // try to connect on channel1
232         $state = $this->channel1->getConnectivityState(true);
233         $this->waitUntilNotIdle($this->channel1);
234
235         // both channels should now be in the CONNECTING state
236         $state = $this->channel1->getConnectivityState();
237         $this->assertConnecting($state);
238         $state = $this->channel2->getConnectivityState();
239         $this->assertConnecting($state);
240
241         $this->channel1->close();
242         $this->channel2->close();
243     }
244
245     public function testPersistentChannelDifferentHost()
246     {
247         // two different underlying channels because different hostname
248         $this->channel1 = new Grpc\Channel('localhost:50015', [
249             "grpc_target_persist_bound" => 3,
250         ]);
251         $this->channel2 = new Grpc\Channel('localhost:50016', []);
252
253         // both channels should be IDLE
254         $state = $this->channel1->getConnectivityState();
255         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
256         $state = $this->channel2->getConnectivityState();
257         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
258
259         // try to connect on channel1
260         $state = $this->channel1->getConnectivityState(true);
261         $this->waitUntilNotIdle($this->channel1);
262
263         // channel1 should now be in the CONNECTING state
264         $state = $this->channel1->getConnectivityState();
265         $this->assertConnecting($state);
266         // channel2 should still be in the IDLE state
267         $state = $this->channel2->getConnectivityState();
268         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
269
270         $this->channel1->close();
271         $this->channel2->close();
272     }
273
274     public function testPersistentChannelSameArgs()
275     {
276         $this->channel1 = new Grpc\Channel('localhost:50017', [
277           "grpc_target_persist_bound" => 3,
278           "abc" => "def",
279           ]);
280         $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
281
282         // try to connect on channel1
283         $state = $this->channel1->getConnectivityState(true);
284         $this->waitUntilNotIdle($this->channel1);
285
286         $state = $this->channel1->getConnectivityState();
287         $this->assertConnecting($state);
288         $state = $this->channel2->getConnectivityState();
289         $this->assertConnecting($state);
290
291         $this->channel1->close();
292         $this->channel2->close();
293     }
294
295     public function testPersistentChannelDifferentArgs()
296     {
297         $this->channel1 = new Grpc\Channel('localhost:50018', [
298             "grpc_target_persist_bound" => 3,
299           ]);
300         $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
301
302         // try to connect on channel1
303         $state = $this->channel1->getConnectivityState(true);
304         $this->waitUntilNotIdle($this->channel1);
305
306         $state = $this->channel1->getConnectivityState();
307         $this->assertConnecting($state);
308         $state = $this->channel2->getConnectivityState();
309         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
310
311         $this->channel1->close();
312         $this->channel2->close();
313     }
314
315     public function persistentChannelSameChannelCredentialsProvider(): array
316     {
317         return [
318             [
319                 Grpc\ChannelCredentials::createSsl(),
320                 Grpc\ChannelCredentials::createSsl(),
321                 50301,
322             ],
323             [
324                 Grpc\ChannelCredentials::createSsl(
325                     file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
326                 ),
327                 Grpc\ChannelCredentials::createSsl(
328                     file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
329                 ),
330                 50302,
331             ],
332             [
333                 Grpc\ChannelCredentials::createInSecure(),
334                 Grpc\ChannelCredentials::createInSecure(),
335                 50303,
336             ],
337             [
338                 \Grpc\ChannelCredentials::createXds(
339                     \Grpc\ChannelCredentials::createSsl()
340                 ),
341                 \Grpc\ChannelCredentials::createXds(
342                     \Grpc\ChannelCredentials::createSsl()
343                 ),
344                 50304,
345             ],
346             [
347                 \Grpc\ChannelCredentials::createXds(
348                     \Grpc\ChannelCredentials::createSsl()
349                 ),
350                 \Grpc\ChannelCredentials::createXds(
351                     \Grpc\ChannelCredentials::createSsl()
352                 ),
353                 50305,
354             ],
355             [
356                 \Grpc\ChannelCredentials::createXds(
357                     \Grpc\ChannelCredentials::createSsl(
358                         file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
359                     )
360                 ),
361                 \Grpc\ChannelCredentials::createXds(
362                     \Grpc\ChannelCredentials::createSsl(
363                         file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
364                     )
365                 ),
366                 50306,
367             ],
368             /*
369             [
370                 \Grpc\ChannelCredentials::createXds(
371                     \Grpc\ChannelCredentials::createInSecure()
372                 ),
373                 \Grpc\ChannelCredentials::createXds(
374                     \Grpc\ChannelCredentials::createInSecure()
375                 ),
376                 50307,
377             ],
378             */
379         ];
380     }
381
382     /**
383      * @dataProvider persistentChannelSameChannelCredentialsProvider
384      */
385     public function testPersistentChannelSameChannelCredentials(
386         $creds1,
387         $creds2,
388         $port
389     ) {
390         $this->channel1 = new Grpc\Channel(
391             'localhost:' . $port,
392             [
393                 "credentials" => $creds1,
394                 "grpc_target_persist_bound" => 3,
395             ]
396         );
397         $this->channel2 = new Grpc\Channel(
398             'localhost:' . $port,
399             ["credentials" => $creds2]
400         );
401
402         // try to connect on channel1
403         $state = $this->channel1->getConnectivityState(true);
404         $this->waitUntilNotIdle($this->channel1);
405
406         $state = $this->channel1->getConnectivityState();
407         $this->assertConnecting($state);
408         $state = $this->channel2->getConnectivityState();
409         $this->assertConnecting($state);
410
411         $this->channel1->close();
412         $this->channel2->close();
413     }
414
415     public function persistentChannelDifferentChannelCredentialsProvider(): array
416     {
417         return [
418             [
419                 Grpc\ChannelCredentials::createSsl(),
420                 Grpc\ChannelCredentials::createSsl(
421                     file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
422                 ),
423                 50351,
424             ],
425             [
426                 Grpc\ChannelCredentials::createSsl(),
427                 Grpc\ChannelCredentials::createInsecure(),
428                 50352,
429             ],
430             [
431                 \Grpc\ChannelCredentials::createXds(
432                     \Grpc\ChannelCredentials::createSsl()
433                 ),
434                 \Grpc\ChannelCredentials::createXds(
435                     \Grpc\ChannelCredentials::createSsl(
436                         file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
437                     )
438                 ),
439                 50353,
440             ],
441             /*
442             [
443                 \Grpc\ChannelCredentials::createXds(
444                     \Grpc\ChannelCredentials::createSsl()
445                 ),
446                 \Grpc\ChannelCredentials::createXds(
447                     \Grpc\ChannelCredentials::createInsecure()
448                 ),
449                 50354,
450             ],
451             [
452                 \Grpc\ChannelCredentials::createInsecure(),
453                 \Grpc\ChannelCredentials::createXds(
454                     \Grpc\ChannelCredentials::createInsecure()
455                 ),
456                 50355,
457             ],
458             */
459             [
460                 \Grpc\ChannelCredentials::createSsl(),
461                 \Grpc\ChannelCredentials::createXds(
462                     \Grpc\ChannelCredentials::createSsl()
463                 ),
464                 50356,
465             ],
466         ];
467     }
468
469     /**
470      * @dataProvider persistentChannelDifferentChannelCredentialsProvider
471      */
472     public function testPersistentChannelDifferentChannelCredentials(
473         $creds1,
474         $creds2,
475         $port
476     ) {
477
478         $this->channel1 = new Grpc\Channel(
479             'localhost:' . $port,
480             [
481                 "credentials" => $creds1,
482                 "grpc_target_persist_bound" => 3,
483             ]
484         );
485         $this->channel2 = new Grpc\Channel(
486             'localhost:' . $port,
487             ["credentials" => $creds2]
488         );
489
490         // try to connect on channel1
491         $state = $this->channel1->getConnectivityState(true);
492         $this->waitUntilNotIdle($this->channel1);
493
494         $state = $this->channel1->getConnectivityState();
495         $this->assertConnecting($state);
496         $state = $this->channel2->getConnectivityState();
497         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
498
499         $this->channel1->close();
500         $this->channel2->close();
501     }
502
503     public function testPersistentChannelSharedChannelClose1()
504     {
505         // same underlying channel
506         $this->channel1 = new Grpc\Channel('localhost:50123', [
507             "grpc_target_persist_bound" => 3,
508         ]);
509         $this->channel2 = new Grpc\Channel('localhost:50123', []);
510
511         // close channel1
512         $this->channel1->close();
513
514         // channel2 can still be use. We need to exclude the possible that
515         // in testPersistentChannelSharedChannelClose2, the exception is thrown
516         // by channel1.
517         $state = $this->channel2->getConnectivityState();
518         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
519     }
520
521     public function testPersistentChannelSharedChannelClose2()
522     {
523         $this->expectException(\RuntimeException::class);
524         // same underlying channel
525         $this->channel1 = new Grpc\Channel('localhost:50223', [
526             "grpc_target_persist_bound" => 3,
527         ]);
528         $this->channel2 = new Grpc\Channel('localhost:50223', []);
529
530         // close channel1
531         $this->channel1->close();
532
533         // channel2 can still be use
534         $state = $this->channel2->getConnectivityState();
535         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
536
537         // channel 1 is closed
538         $state = $this->channel1->getConnectivityState();
539     }
540
541     public function testPersistentChannelCreateAfterClose()
542     {
543         $this->channel1 = new Grpc\Channel('localhost:50024', [
544             "grpc_target_persist_bound" => 3,
545         ]);
546
547         $this->channel1->close();
548
549         $this->channel2 = new Grpc\Channel('localhost:50024', []);
550         $state = $this->channel2->getConnectivityState();
551         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
552
553         $this->channel2->close();
554     }
555
556     public function testPersistentChannelSharedMoreThanTwo()
557     {
558         $this->channel1 = new Grpc\Channel('localhost:50025', [
559             "grpc_target_persist_bound" => 3,
560         ]);
561         $this->channel2 = new Grpc\Channel('localhost:50025', []);
562         $this->channel3 = new Grpc\Channel('localhost:50025', []);
563
564         // try to connect on channel1
565         $state = $this->channel1->getConnectivityState(true);
566         $this->waitUntilNotIdle($this->channel1);
567
568         // all 3 channels should be in CONNECTING state
569         $state = $this->channel1->getConnectivityState();
570         $this->assertConnecting($state);
571         $state = $this->channel2->getConnectivityState();
572         $this->assertConnecting($state);
573         $state = $this->channel3->getConnectivityState();
574         $this->assertConnecting($state);
575
576         $this->channel1->close();
577     }
578
579     public function callbackFunc($context)
580     {
581         return [];
582     }
583
584     public function callbackFunc2($context)
585     {
586         return ["k1" => "v1"];
587     }
588
589     public function testPersistentChannelWithCallCredentials()
590     {
591         $creds = Grpc\ChannelCredentials::createSsl();
592         $callCreds = Grpc\CallCredentials::createFromPlugin(
593             [$this, 'callbackFunc']);
594         $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
595             $creds, $callCreds);
596
597         // If a ChannelCredentials object is composed with a
598         // CallCredentials object, the underlying grpc channel will
599         // always be created new and NOT persisted.
600         $this->channel1 = new Grpc\Channel('localhost:50026',
601                                            ["credentials" =>
602                                             $credsWithCallCreds,
603                                             "grpc_target_persist_bound" => 3,
604                                             ]);
605         $this->channel2 = new Grpc\Channel('localhost:50026',
606                                            ["credentials" =>
607                                             $credsWithCallCreds]);
608
609         // try to connect on channel1
610         $state = $this->channel1->getConnectivityState(true);
611         $this->waitUntilNotIdle($this->channel1);
612
613         $state = $this->channel1->getConnectivityState();
614         $this->assertConnecting($state);
615         $state = $this->channel2->getConnectivityState();
616         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
617
618         $this->channel1->close();
619         $this->channel2->close();
620     }
621
622     public function testPersistentChannelWithDifferentCallCredentials()
623     {
624         $callCreds1 = Grpc\CallCredentials::createFromPlugin(
625             [$this, 'callbackFunc']);
626         $callCreds2 = Grpc\CallCredentials::createFromPlugin(
627             [$this, 'callbackFunc2']);
628
629         $creds1 = Grpc\ChannelCredentials::createSsl();
630         $creds2 = Grpc\ChannelCredentials::createComposite(
631             $creds1, $callCreds1);
632         $creds3 = Grpc\ChannelCredentials::createComposite(
633             $creds1, $callCreds2);
634
635         // Similar to the test above, anytime a ChannelCredentials
636         // object is composed with a CallCredentials object, the
637         // underlying grpc channel will always be separate and not
638         // persisted
639         $this->channel1 = new Grpc\Channel('localhost:50027',
640                                            ["credentials" => $creds1,
641                                             "grpc_target_persist_bound" => 3,
642                                             ]);
643         $this->channel2 = new Grpc\Channel('localhost:50027',
644                                            ["credentials" => $creds2]);
645         $this->channel3 = new Grpc\Channel('localhost:50027',
646                                            ["credentials" => $creds3]);
647
648         // try to connect on channel1
649         $state = $this->channel1->getConnectivityState(true);
650         $this->waitUntilNotIdle($this->channel1);
651
652         $state = $this->channel1->getConnectivityState();
653         $this->assertConnecting($state);
654         $state = $this->channel2->getConnectivityState();
655         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
656         $state = $this->channel3->getConnectivityState();
657         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
658
659         $this->channel1->close();
660         $this->channel2->close();
661         $this->channel3->close();
662     }
663
664     public function testPersistentChannelForceNew()
665     {
666         $this->channel1 = new Grpc\Channel('localhost:50028', [
667             "grpc_target_persist_bound" => 2,
668         ]);
669         // even though all the channel params are the same, channel2
670         // has a new and different underlying channel
671         $this->channel2 = new Grpc\Channel('localhost:50028',
672                                            ["force_new" => true]);
673
674         // try to connect on channel1
675         $state = $this->channel1->getConnectivityState(true);
676         $this->waitUntilNotIdle($this->channel1);
677
678         $state = $this->channel1->getConnectivityState();
679         $this->assertConnecting($state);
680         $state = $this->channel2->getConnectivityState();
681         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
682
683         $this->channel1->close();
684         $this->channel2->close();
685     }
686
687     public function testPersistentChannelForceNewOldChannelIdle1()
688     {
689
690         $this->channel1 = new Grpc\Channel('localhost:50029', [
691             "grpc_target_persist_bound" => 2,
692         ]);
693         $this->channel2 = new Grpc\Channel('localhost:50029',
694                                            ["force_new" => true]);
695         // channel3 shares with channel1
696         $this->channel3 = new Grpc\Channel('localhost:50029', []);
697
698         // try to connect on channel2
699         $state = $this->channel2->getConnectivityState(true);
700         $this->waitUntilNotIdle($this->channel2);
701         $state = $this->channel1->getConnectivityState();
702         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
703         $state = $this->channel2->getConnectivityState();
704         $this->assertConnecting($state);
705         $state = $this->channel3->getConnectivityState();
706         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
707
708         $this->channel1->close();
709         $this->channel2->close();
710     }
711
712     public function testPersistentChannelForceNewOldChannelIdle2()
713     {
714
715         $this->channel1 = new Grpc\Channel('localhost:50032', [
716             "grpc_target_persist_bound" => 2,
717         ]);
718         $this->channel2 = new Grpc\Channel('localhost:50032', []);
719
720         // try to connect on channel2
721         $state = $this->channel1->getConnectivityState(true);
722         $this->waitUntilNotIdle($this->channel2);
723         $state = $this->channel1->getConnectivityState();
724         $this->assertConnecting($state);
725         $state = $this->channel2->getConnectivityState();
726         $this->assertConnecting($state);
727
728         $this->channel1->close();
729         $this->channel2->close();
730     }
731
732     public function testPersistentChannelForceNewOldChannelClose1()
733     {
734
735         $this->channel1 = new Grpc\Channel('localhost:50130', [
736             "grpc_target_persist_bound" => 2,
737         ]);
738         $this->channel2 = new Grpc\Channel('localhost:50130',
739                                            ["force_new" => true]);
740         // channel3 shares with channel1
741         $this->channel3 = new Grpc\Channel('localhost:50130', []);
742
743         $this->channel1->close();
744
745         $state = $this->channel2->getConnectivityState();
746         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
747
748         // channel3 is still usable. We need to exclude the possibility that in
749         // testPersistentChannelForceNewOldChannelClose2, the exception is thrown
750         // by channel1 and channel2.
751         $state = $this->channel3->getConnectivityState();
752         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
753     }
754
755     public function testPersistentChannelForceNewOldChannelClose2()
756     {
757         $this->expectException(\RuntimeException::class);
758         $this->channel1 = new Grpc\Channel('localhost:50230', [
759             "grpc_target_persist_bound" => 2,
760         ]);
761         $this->channel2 = new Grpc\Channel('localhost:50230',
762           ["force_new" => true]);
763         // channel3 shares with channel1
764         $this->channel3 = new Grpc\Channel('localhost:50230', []);
765
766         $this->channel1->close();
767
768         $state = $this->channel2->getConnectivityState();
769         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
770
771         // channel3 is still usable
772         $state = $this->channel3->getConnectivityState();
773         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
774
775         // channel 1 is closed
776         $this->channel1->getConnectivityState();
777     }
778
779     public function testPersistentChannelForceNewNewChannelClose()
780     {
781
782         $this->channel1 = new Grpc\Channel('localhost:50031', [
783             "grpc_target_persist_bound" => 2,
784         ]);
785         $this->channel2 = new Grpc\Channel('localhost:50031',
786                                            ["force_new" => true]);
787         $this->channel3 = new Grpc\Channel('localhost:50031', []);
788
789         $this->channel2->close();
790
791         $state = $this->channel1->getConnectivityState();
792         $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
793
794         // can still connect on channel1
795         $state = $this->channel1->getConnectivityState(true);
796         $this->waitUntilNotIdle($this->channel1);
797
798         $state = $this->channel1->getConnectivityState();
799         $this->assertConnecting($state);
800
801         $this->channel1->close();
802     }
803 }