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