4 * Copyright 2018 gRPC authors.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 class ChannelTest extends \PHPUnit\Framework\TestCase
22 public function setUp(): void
26 public function tearDown(): void
28 if (!empty($this->channel)) {
29 $this->channel->close();
33 public function testInsecureCredentials()
35 $this->channel = new Grpc\Channel('localhost:50000',
36 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
37 $this->assertSame('Grpc\Channel', get_class($this->channel));
40 public function testConstructorCreateSsl()
42 $channel = new Grpc\Channel('localhost:50033',
43 ['credentials' => \Grpc\ChannelCredentials::createSsl()]);
44 $this->assertNotNull($channel);
47 public function testCreateXdsWithSsl()
49 $xdsCreds = \Grpc\ChannelCredentials::createXds(
50 \Grpc\ChannelCredentials::createSsl()
52 $this->assertNotNull($xdsCreds);
55 public function testCreateXdsWithInsecure() {
56 $xdsCreds = \Grpc\ChannelCredentials::createXds(
57 \Grpc\ChannelCredentials::createInsecure()
59 $this->assertNotNull($xdsCreds);
62 public function testCreateXdsWithNull() {
63 $this->expectException(\InvalidArgumentException::class);
64 $xdsCreds = \Grpc\ChannelCredentials::createXds(null);
67 public function testCreateXdsWithInvalidType() {
68 $this->expectException(\TypeError::class);
69 $xdsCreds = \Grpc\ChannelCredentials::createXds("invalid-type");
72 public function testGetConnectivityState()
74 $this->channel = new Grpc\Channel('localhost:50001',
75 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
76 $state = $this->channel->getConnectivityState();
77 $this->assertEquals(0, $state);
80 public function testGetConnectivityStateWithInt()
82 $this->channel = new Grpc\Channel('localhost:50002',
83 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
84 $state = $this->channel->getConnectivityState(123);
85 $this->assertEquals(0, $state);
88 public function testGetConnectivityStateWithString()
90 $this->channel = new Grpc\Channel('localhost:50003',
91 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
92 $state = $this->channel->getConnectivityState('hello');
93 $this->assertEquals(0, $state);
96 public function testGetConnectivityStateWithBool()
98 $this->channel = new Grpc\Channel('localhost:50004',
99 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
100 $state = $this->channel->getConnectivityState(true);
101 $this->assertEquals(0, $state);
104 public function testGetTarget()
106 $this->channel = new Grpc\Channel('localhost:50005',
107 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
108 $target = $this->channel->getTarget();
109 $this->assertTrue(is_string($target));
112 public function testWatchConnectivityState()
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);
126 public function testClose()
128 $this->channel = new Grpc\Channel('localhost:50007',
129 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
130 $this->assertNotNull($this->channel);
131 $this->channel->close();
134 public function testInvalidConstructorWithNull()
136 $this->expectException(\InvalidArgumentException::class);
137 $this->channel = new Grpc\Channel();
138 $this->assertNull($this->channel);
141 public function testInvalidConstructorWith()
143 $this->expectException(\InvalidArgumentException::class);
144 $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
145 $this->assertNull($this->channel);
148 public function testInvalidCredentials()
150 $this->expectException(\InvalidArgumentException::class);
151 $this->channel = new Grpc\Channel('localhost:50009',
152 ['credentials' => new Grpc\Timeval(100)]);
155 public function testInvalidOptionsArray()
157 $this->expectException(\InvalidArgumentException::class);
158 $this->channel = new Grpc\Channel('localhost:50010',
162 public function testInvalidGetConnectivityStateWithArray()
164 $this->expectException(\InvalidArgumentException::class);
165 $this->channel = new Grpc\Channel('localhost:50011',
166 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
167 $this->channel->getConnectivityState([]);
170 public function testInvalidWatchConnectivityState()
172 $this->expectException(\InvalidArgumentException::class);
173 $this->channel = new Grpc\Channel('localhost:50012',
174 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
175 $this->channel->watchConnectivityState([]);
178 public function testInvalidWatchConnectivityState2()
180 $this->expectException(\InvalidArgumentException::class);
181 $this->channel = new Grpc\Channel('localhost:50013',
182 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
183 $this->channel->watchConnectivityState(1, 'hi');
187 public function assertConnecting($state) {
188 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
189 $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
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,
201 $this->assertTrue(false);
204 public function testPersistentChannelSameHost()
206 $this->channel1 = new Grpc\Channel('localhost:50014', [
207 "grpc_target_persist_bound" => 3,
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', []);
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);
219 // try to connect on channel1
220 $state = $this->channel1->getConnectivityState(true);
221 $this->waitUntilNotIdle($this->channel1);
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);
229 $this->channel1->close();
230 $this->channel2->close();
233 public function testPersistentChannelDifferentHost()
235 // two different underlying channels because different hostname
236 $this->channel1 = new Grpc\Channel('localhost:50015', [
237 "grpc_target_persist_bound" => 3,
239 $this->channel2 = new Grpc\Channel('localhost:50016', []);
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);
247 // try to connect on channel1
248 $state = $this->channel1->getConnectivityState(true);
249 $this->waitUntilNotIdle($this->channel1);
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);
258 $this->channel1->close();
259 $this->channel2->close();
262 public function testPersistentChannelSameArgs()
264 $this->channel1 = new Grpc\Channel('localhost:50017', [
265 "grpc_target_persist_bound" => 3,
268 $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
270 // try to connect on channel1
271 $state = $this->channel1->getConnectivityState(true);
272 $this->waitUntilNotIdle($this->channel1);
274 $state = $this->channel1->getConnectivityState();
275 $this->assertConnecting($state);
276 $state = $this->channel2->getConnectivityState();
277 $this->assertConnecting($state);
279 $this->channel1->close();
280 $this->channel2->close();
283 public function testPersistentChannelDifferentArgs()
285 $this->channel1 = new Grpc\Channel('localhost:50018', [
286 "grpc_target_persist_bound" => 3,
288 $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
290 // try to connect on channel1
291 $state = $this->channel1->getConnectivityState(true);
292 $this->waitUntilNotIdle($this->channel1);
294 $state = $this->channel1->getConnectivityState();
295 $this->assertConnecting($state);
296 $state = $this->channel2->getConnectivityState();
297 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
299 $this->channel1->close();
300 $this->channel2->close();
303 public function persistentChannelSameChannelCredentialsProvider(): array
307 Grpc\ChannelCredentials::createSsl(),
308 Grpc\ChannelCredentials::createSsl(),
312 Grpc\ChannelCredentials::createSsl(
313 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
315 Grpc\ChannelCredentials::createSsl(
316 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
321 Grpc\ChannelCredentials::createInSecure(),
322 Grpc\ChannelCredentials::createInSecure(),
326 \Grpc\ChannelCredentials::createXds(
327 \Grpc\ChannelCredentials::createSsl()
329 \Grpc\ChannelCredentials::createXds(
330 \Grpc\ChannelCredentials::createSsl()
335 \Grpc\ChannelCredentials::createXds(
336 \Grpc\ChannelCredentials::createSsl()
338 \Grpc\ChannelCredentials::createXds(
339 \Grpc\ChannelCredentials::createSsl()
344 \Grpc\ChannelCredentials::createXds(
345 \Grpc\ChannelCredentials::createSsl(
346 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
349 \Grpc\ChannelCredentials::createXds(
350 \Grpc\ChannelCredentials::createSsl(
351 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
357 \Grpc\ChannelCredentials::createXds(
358 \Grpc\ChannelCredentials::createInSecure()
360 \Grpc\ChannelCredentials::createXds(
361 \Grpc\ChannelCredentials::createInSecure()
369 * @dataProvider persistentChannelSameChannelCredentialsProvider
371 public function testPersistentChannelSameChannelCredentials(
376 $this->channel1 = new Grpc\Channel(
377 'localhost:' . $port,
379 "credentials" => $creds1,
380 "grpc_target_persist_bound" => 3,
383 $this->channel2 = new Grpc\Channel(
384 'localhost:' . $port,
385 ["credentials" => $creds2]
388 // try to connect on channel1
389 $state = $this->channel1->getConnectivityState(true);
390 $this->waitUntilNotIdle($this->channel1);
392 $state = $this->channel1->getConnectivityState();
393 $this->assertConnecting($state);
394 $state = $this->channel2->getConnectivityState();
395 $this->assertConnecting($state);
397 $this->channel1->close();
398 $this->channel2->close();
401 public function persistentChannelDifferentChannelCredentialsProvider(): array
405 Grpc\ChannelCredentials::createSsl(),
406 Grpc\ChannelCredentials::createSsl(
407 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
412 Grpc\ChannelCredentials::createSsl(),
413 Grpc\ChannelCredentials::createInsecure(),
417 \Grpc\ChannelCredentials::createXds(
418 \Grpc\ChannelCredentials::createSsl()
420 \Grpc\ChannelCredentials::createXds(
421 \Grpc\ChannelCredentials::createSsl(
422 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
428 \Grpc\ChannelCredentials::createXds(
429 \Grpc\ChannelCredentials::createSsl()
431 \Grpc\ChannelCredentials::createXds(
432 \Grpc\ChannelCredentials::createInsecure()
437 \Grpc\ChannelCredentials::createInsecure(),
438 \Grpc\ChannelCredentials::createXds(
439 \Grpc\ChannelCredentials::createInsecure()
444 \Grpc\ChannelCredentials::createSsl(),
445 \Grpc\ChannelCredentials::createXds(
446 \Grpc\ChannelCredentials::createSsl()
454 * @dataProvider persistentChannelDifferentChannelCredentialsProvider
456 public function testPersistentChannelDifferentChannelCredentials(
462 $this->channel1 = new Grpc\Channel(
463 'localhost:' . $port,
465 "credentials" => $creds1,
466 "grpc_target_persist_bound" => 3,
469 $this->channel2 = new Grpc\Channel(
470 'localhost:' . $port,
471 ["credentials" => $creds2]
474 // try to connect on channel1
475 $state = $this->channel1->getConnectivityState(true);
476 $this->waitUntilNotIdle($this->channel1);
478 $state = $this->channel1->getConnectivityState();
479 $this->assertConnecting($state);
480 $state = $this->channel2->getConnectivityState();
481 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
483 $this->channel1->close();
484 $this->channel2->close();
487 public function testPersistentChannelSharedChannelClose1()
489 // same underlying channel
490 $this->channel1 = new Grpc\Channel('localhost:50123', [
491 "grpc_target_persist_bound" => 3,
493 $this->channel2 = new Grpc\Channel('localhost:50123', []);
496 $this->channel1->close();
498 // channel2 can still be use. We need to exclude the possible that
499 // in testPersistentChannelSharedChannelClose2, the exception is thrown
501 $state = $this->channel2->getConnectivityState();
502 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
505 public function testPersistentChannelSharedChannelClose2()
507 $this->expectException(\RuntimeException::class);
508 // same underlying channel
509 $this->channel1 = new Grpc\Channel('localhost:50223', [
510 "grpc_target_persist_bound" => 3,
512 $this->channel2 = new Grpc\Channel('localhost:50223', []);
515 $this->channel1->close();
517 // channel2 can still be use
518 $state = $this->channel2->getConnectivityState();
519 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
521 // channel 1 is closed
522 $state = $this->channel1->getConnectivityState();
525 public function testPersistentChannelCreateAfterClose()
527 $this->channel1 = new Grpc\Channel('localhost:50024', [
528 "grpc_target_persist_bound" => 3,
531 $this->channel1->close();
533 $this->channel2 = new Grpc\Channel('localhost:50024', []);
534 $state = $this->channel2->getConnectivityState();
535 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
537 $this->channel2->close();
540 public function testPersistentChannelSharedMoreThanTwo()
542 $this->channel1 = new Grpc\Channel('localhost:50025', [
543 "grpc_target_persist_bound" => 3,
545 $this->channel2 = new Grpc\Channel('localhost:50025', []);
546 $this->channel3 = new Grpc\Channel('localhost:50025', []);
548 // try to connect on channel1
549 $state = $this->channel1->getConnectivityState(true);
550 $this->waitUntilNotIdle($this->channel1);
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);
560 $this->channel1->close();
563 public function callbackFunc($context)
568 public function callbackFunc2($context)
570 return ["k1" => "v1"];
573 public function testPersistentChannelWithCallCredentials()
575 $creds = Grpc\ChannelCredentials::createSsl();
576 $callCreds = Grpc\CallCredentials::createFromPlugin(
577 [$this, 'callbackFunc']);
578 $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
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',
587 "grpc_target_persist_bound" => 3,
589 $this->channel2 = new Grpc\Channel('localhost:50026',
591 $credsWithCallCreds]);
593 // try to connect on channel1
594 $state = $this->channel1->getConnectivityState(true);
595 $this->waitUntilNotIdle($this->channel1);
597 $state = $this->channel1->getConnectivityState();
598 $this->assertConnecting($state);
599 $state = $this->channel2->getConnectivityState();
600 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
602 $this->channel1->close();
603 $this->channel2->close();
606 public function testPersistentChannelWithDifferentCallCredentials()
608 $callCreds1 = Grpc\CallCredentials::createFromPlugin(
609 [$this, 'callbackFunc']);
610 $callCreds2 = Grpc\CallCredentials::createFromPlugin(
611 [$this, 'callbackFunc2']);
613 $creds1 = Grpc\ChannelCredentials::createSsl();
614 $creds2 = Grpc\ChannelCredentials::createComposite(
615 $creds1, $callCreds1);
616 $creds3 = Grpc\ChannelCredentials::createComposite(
617 $creds1, $callCreds2);
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
623 $this->channel1 = new Grpc\Channel('localhost:50027',
624 ["credentials" => $creds1,
625 "grpc_target_persist_bound" => 3,
627 $this->channel2 = new Grpc\Channel('localhost:50027',
628 ["credentials" => $creds2]);
629 $this->channel3 = new Grpc\Channel('localhost:50027',
630 ["credentials" => $creds3]);
632 // try to connect on channel1
633 $state = $this->channel1->getConnectivityState(true);
634 $this->waitUntilNotIdle($this->channel1);
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);
643 $this->channel1->close();
644 $this->channel2->close();
645 $this->channel3->close();
648 public function testPersistentChannelForceNew()
650 $this->channel1 = new Grpc\Channel('localhost:50028', [
651 "grpc_target_persist_bound" => 2,
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]);
658 // try to connect on channel1
659 $state = $this->channel1->getConnectivityState(true);
660 $this->waitUntilNotIdle($this->channel1);
662 $state = $this->channel1->getConnectivityState();
663 $this->assertConnecting($state);
664 $state = $this->channel2->getConnectivityState();
665 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
667 $this->channel1->close();
668 $this->channel2->close();
671 public function testPersistentChannelForceNewOldChannelIdle1()
674 $this->channel1 = new Grpc\Channel('localhost:50029', [
675 "grpc_target_persist_bound" => 2,
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', []);
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);
692 $this->channel1->close();
693 $this->channel2->close();
696 public function testPersistentChannelForceNewOldChannelIdle2()
699 $this->channel1 = new Grpc\Channel('localhost:50032', [
700 "grpc_target_persist_bound" => 2,
702 $this->channel2 = new Grpc\Channel('localhost:50032', []);
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);
712 $this->channel1->close();
713 $this->channel2->close();
716 public function testPersistentChannelForceNewOldChannelClose1()
719 $this->channel1 = new Grpc\Channel('localhost:50130', [
720 "grpc_target_persist_bound" => 2,
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', []);
727 $this->channel1->close();
729 $state = $this->channel2->getConnectivityState();
730 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
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);
739 public function testPersistentChannelForceNewOldChannelClose2()
741 $this->expectException(\RuntimeException::class);
742 $this->channel1 = new Grpc\Channel('localhost:50230', [
743 "grpc_target_persist_bound" => 2,
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', []);
750 $this->channel1->close();
752 $state = $this->channel2->getConnectivityState();
753 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
755 // channel3 is still usable
756 $state = $this->channel3->getConnectivityState();
757 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
759 // channel 1 is closed
760 $this->channel1->getConnectivityState();
763 public function testPersistentChannelForceNewNewChannelClose()
766 $this->channel1 = new Grpc\Channel('localhost:50031', [
767 "grpc_target_persist_bound" => 2,
769 $this->channel2 = new Grpc\Channel('localhost:50031',
770 ["force_new" => true]);
771 $this->channel3 = new Grpc\Channel('localhost:50031', []);
773 $this->channel2->close();
775 $state = $this->channel1->getConnectivityState();
776 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
778 // can still connect on channel1
779 $state = $this->channel1->getConnectivityState(true);
780 $this->waitUntilNotIdle($this->channel1);
782 $state = $this->channel1->getConnectivityState();
783 $this->assertConnecting($state);
785 $this->channel1->close();