• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
20class 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}
788