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