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 disabled_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()
69 $expected = $this->logicalOr(
71 new \PHPUnit\Framework\Constraint\Exception(\InvalidArgumentException::class),
73 new \PHPUnit\Framework\Constraint\Exception(\TypeError::class)
76 $xdsCreds = \Grpc\ChannelCredentials::createXds("invalid-type");
77 } catch (\Throwable $exception) {
78 $this->assertThat($exception, $expected);
81 $this->assertThat(null, $expected);
84 public function testGetConnectivityState()
86 $this->channel = new Grpc\Channel('localhost:50001',
87 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
88 $state = $this->channel->getConnectivityState();
89 $this->assertEquals(0, $state);
92 public function testGetConnectivityStateWithInt()
94 $this->channel = new Grpc\Channel('localhost:50002',
95 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
96 $state = $this->channel->getConnectivityState(123);
97 $this->assertEquals(0, $state);
100 public function testGetConnectivityStateWithString()
102 $this->channel = new Grpc\Channel('localhost:50003',
103 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
104 $state = $this->channel->getConnectivityState('hello');
105 $this->assertEquals(0, $state);
108 public function testGetConnectivityStateWithBool()
110 $this->channel = new Grpc\Channel('localhost:50004',
111 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
112 $state = $this->channel->getConnectivityState(true);
113 $this->assertEquals(0, $state);
116 public function testGetTarget()
118 $this->channel = new Grpc\Channel('localhost:50005',
119 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
120 $target = $this->channel->getTarget();
121 $this->assertTrue(is_string($target));
124 public function testWatchConnectivityState()
126 $this->channel = new Grpc\Channel('localhost:50006',
127 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
128 $now = Grpc\Timeval::now();
129 $deadline = $now->add(new Grpc\Timeval(100*1000)); // 100ms
130 // we act as if 'CONNECTING'(=1) was the last state
131 // we saw, so the default state of 'IDLE' should be delivered instantly
132 $state = $this->channel->watchConnectivityState(1, $deadline);
133 $this->assertTrue($state);
138 public function testClose()
140 $this->channel = new Grpc\Channel('localhost:50007',
141 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
142 $this->assertNotNull($this->channel);
143 $this->channel->close();
146 public function testInvalidConstructorWithNull()
148 $this->expectException(\InvalidArgumentException::class);
149 $this->channel = new Grpc\Channel();
150 $this->assertNull($this->channel);
153 public function testInvalidConstructorWith()
155 $this->expectException(\InvalidArgumentException::class);
156 $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
157 $this->assertNull($this->channel);
160 public function testInvalidCredentials()
162 $this->expectException(\InvalidArgumentException::class);
163 $this->channel = new Grpc\Channel('localhost:50009',
164 ['credentials' => new Grpc\Timeval(100)]);
167 public function testInvalidOptionsArray()
169 $this->expectException(\InvalidArgumentException::class);
170 $this->channel = new Grpc\Channel('localhost:50010',
174 public function testInvalidGetConnectivityStateWithArray()
176 $this->expectException(\InvalidArgumentException::class);
177 $this->channel = new Grpc\Channel('localhost:50011',
178 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
179 $this->channel->getConnectivityState([]);
182 public function testInvalidWatchConnectivityState()
184 $this->expectException(\InvalidArgumentException::class);
185 $this->channel = new Grpc\Channel('localhost:50012',
186 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
187 $this->channel->watchConnectivityState([]);
190 public function testInvalidWatchConnectivityState2()
192 $this->expectException(\InvalidArgumentException::class);
193 $this->channel = new Grpc\Channel('localhost:50013',
194 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
195 $this->channel->watchConnectivityState(1, 'hi');
199 public function assertConnecting($state) {
200 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
201 $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
204 public function waitUntilNotIdle($channel) {
205 for ($i = 0; $i < 10; $i++) {
206 $now = Grpc\Timeval::now();
207 $deadline = $now->add(new Grpc\Timeval(1000));
208 if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
213 $this->assertTrue(false);
216 public function testPersistentChannelSameHost()
218 $this->channel1 = new Grpc\Channel('localhost:50014', [
219 "grpc_target_persist_bound" => 3,
221 // the underlying grpc channel is the same by default
222 // when connecting to the same host
223 $this->channel2 = new Grpc\Channel('localhost:50014', []);
225 // both channels should be IDLE
226 $state = $this->channel1->getConnectivityState();
227 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
228 $state = $this->channel2->getConnectivityState();
229 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
231 // try to connect on channel1
232 $state = $this->channel1->getConnectivityState(true);
233 $this->waitUntilNotIdle($this->channel1);
235 // both channels should now be in the CONNECTING state
236 $state = $this->channel1->getConnectivityState();
237 $this->assertConnecting($state);
238 $state = $this->channel2->getConnectivityState();
239 $this->assertConnecting($state);
241 $this->channel1->close();
242 $this->channel2->close();
245 public function testPersistentChannelDifferentHost()
247 // two different underlying channels because different hostname
248 $this->channel1 = new Grpc\Channel('localhost:50015', [
249 "grpc_target_persist_bound" => 3,
251 $this->channel2 = new Grpc\Channel('localhost:50016', []);
253 // both channels should be IDLE
254 $state = $this->channel1->getConnectivityState();
255 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
256 $state = $this->channel2->getConnectivityState();
257 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
259 // try to connect on channel1
260 $state = $this->channel1->getConnectivityState(true);
261 $this->waitUntilNotIdle($this->channel1);
263 // channel1 should now be in the CONNECTING state
264 $state = $this->channel1->getConnectivityState();
265 $this->assertConnecting($state);
266 // channel2 should still be in the IDLE state
267 $state = $this->channel2->getConnectivityState();
268 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
270 $this->channel1->close();
271 $this->channel2->close();
274 public function testPersistentChannelSameArgs()
276 $this->channel1 = new Grpc\Channel('localhost:50017', [
277 "grpc_target_persist_bound" => 3,
280 $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
282 // try to connect on channel1
283 $state = $this->channel1->getConnectivityState(true);
284 $this->waitUntilNotIdle($this->channel1);
286 $state = $this->channel1->getConnectivityState();
287 $this->assertConnecting($state);
288 $state = $this->channel2->getConnectivityState();
289 $this->assertConnecting($state);
291 $this->channel1->close();
292 $this->channel2->close();
295 public function testPersistentChannelDifferentArgs()
297 $this->channel1 = new Grpc\Channel('localhost:50018', [
298 "grpc_target_persist_bound" => 3,
300 $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
302 // try to connect on channel1
303 $state = $this->channel1->getConnectivityState(true);
304 $this->waitUntilNotIdle($this->channel1);
306 $state = $this->channel1->getConnectivityState();
307 $this->assertConnecting($state);
308 $state = $this->channel2->getConnectivityState();
309 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
311 $this->channel1->close();
312 $this->channel2->close();
315 public function persistentChannelSameChannelCredentialsProvider(): array
319 Grpc\ChannelCredentials::createSsl(),
320 Grpc\ChannelCredentials::createSsl(),
324 Grpc\ChannelCredentials::createSsl(
325 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
327 Grpc\ChannelCredentials::createSsl(
328 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
333 Grpc\ChannelCredentials::createInSecure(),
334 Grpc\ChannelCredentials::createInSecure(),
338 \Grpc\ChannelCredentials::createXds(
339 \Grpc\ChannelCredentials::createSsl()
341 \Grpc\ChannelCredentials::createXds(
342 \Grpc\ChannelCredentials::createSsl()
347 \Grpc\ChannelCredentials::createXds(
348 \Grpc\ChannelCredentials::createSsl()
350 \Grpc\ChannelCredentials::createXds(
351 \Grpc\ChannelCredentials::createSsl()
356 \Grpc\ChannelCredentials::createXds(
357 \Grpc\ChannelCredentials::createSsl(
358 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
361 \Grpc\ChannelCredentials::createXds(
362 \Grpc\ChannelCredentials::createSsl(
363 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
370 \Grpc\ChannelCredentials::createXds(
371 \Grpc\ChannelCredentials::createInSecure()
373 \Grpc\ChannelCredentials::createXds(
374 \Grpc\ChannelCredentials::createInSecure()
383 * @dataProvider persistentChannelSameChannelCredentialsProvider
385 public function testPersistentChannelSameChannelCredentials(
390 $this->channel1 = new Grpc\Channel(
391 'localhost:' . $port,
393 "credentials" => $creds1,
394 "grpc_target_persist_bound" => 3,
397 $this->channel2 = new Grpc\Channel(
398 'localhost:' . $port,
399 ["credentials" => $creds2]
402 // try to connect on channel1
403 $state = $this->channel1->getConnectivityState(true);
404 $this->waitUntilNotIdle($this->channel1);
406 $state = $this->channel1->getConnectivityState();
407 $this->assertConnecting($state);
408 $state = $this->channel2->getConnectivityState();
409 $this->assertConnecting($state);
411 $this->channel1->close();
412 $this->channel2->close();
415 public function persistentChannelDifferentChannelCredentialsProvider(): array
419 Grpc\ChannelCredentials::createSsl(),
420 Grpc\ChannelCredentials::createSsl(
421 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
426 Grpc\ChannelCredentials::createSsl(),
427 Grpc\ChannelCredentials::createInsecure(),
431 \Grpc\ChannelCredentials::createXds(
432 \Grpc\ChannelCredentials::createSsl()
434 \Grpc\ChannelCredentials::createXds(
435 \Grpc\ChannelCredentials::createSsl(
436 file_get_contents(dirname(__FILE__) . '/../data/ca.pem')
443 \Grpc\ChannelCredentials::createXds(
444 \Grpc\ChannelCredentials::createSsl()
446 \Grpc\ChannelCredentials::createXds(
447 \Grpc\ChannelCredentials::createInsecure()
452 \Grpc\ChannelCredentials::createInsecure(),
453 \Grpc\ChannelCredentials::createXds(
454 \Grpc\ChannelCredentials::createInsecure()
460 \Grpc\ChannelCredentials::createSsl(),
461 \Grpc\ChannelCredentials::createXds(
462 \Grpc\ChannelCredentials::createSsl()
470 * @dataProvider persistentChannelDifferentChannelCredentialsProvider
472 public function testPersistentChannelDifferentChannelCredentials(
478 $this->channel1 = new Grpc\Channel(
479 'localhost:' . $port,
481 "credentials" => $creds1,
482 "grpc_target_persist_bound" => 3,
485 $this->channel2 = new Grpc\Channel(
486 'localhost:' . $port,
487 ["credentials" => $creds2]
490 // try to connect on channel1
491 $state = $this->channel1->getConnectivityState(true);
492 $this->waitUntilNotIdle($this->channel1);
494 $state = $this->channel1->getConnectivityState();
495 $this->assertConnecting($state);
496 $state = $this->channel2->getConnectivityState();
497 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
499 $this->channel1->close();
500 $this->channel2->close();
503 public function testPersistentChannelSharedChannelClose1()
505 // same underlying channel
506 $this->channel1 = new Grpc\Channel('localhost:50123', [
507 "grpc_target_persist_bound" => 3,
509 $this->channel2 = new Grpc\Channel('localhost:50123', []);
512 $this->channel1->close();
514 // channel2 can still be use. We need to exclude the possible that
515 // in testPersistentChannelSharedChannelClose2, the exception is thrown
517 $state = $this->channel2->getConnectivityState();
518 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
521 public function testPersistentChannelSharedChannelClose2()
523 $this->expectException(\RuntimeException::class);
524 // same underlying channel
525 $this->channel1 = new Grpc\Channel('localhost:50223', [
526 "grpc_target_persist_bound" => 3,
528 $this->channel2 = new Grpc\Channel('localhost:50223', []);
531 $this->channel1->close();
533 // channel2 can still be use
534 $state = $this->channel2->getConnectivityState();
535 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
537 // channel 1 is closed
538 $state = $this->channel1->getConnectivityState();
541 public function testPersistentChannelCreateAfterClose()
543 $this->channel1 = new Grpc\Channel('localhost:50024', [
544 "grpc_target_persist_bound" => 3,
547 $this->channel1->close();
549 $this->channel2 = new Grpc\Channel('localhost:50024', []);
550 $state = $this->channel2->getConnectivityState();
551 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
553 $this->channel2->close();
556 public function testPersistentChannelSharedMoreThanTwo()
558 $this->channel1 = new Grpc\Channel('localhost:50025', [
559 "grpc_target_persist_bound" => 3,
561 $this->channel2 = new Grpc\Channel('localhost:50025', []);
562 $this->channel3 = new Grpc\Channel('localhost:50025', []);
564 // try to connect on channel1
565 $state = $this->channel1->getConnectivityState(true);
566 $this->waitUntilNotIdle($this->channel1);
568 // all 3 channels should be in CONNECTING state
569 $state = $this->channel1->getConnectivityState();
570 $this->assertConnecting($state);
571 $state = $this->channel2->getConnectivityState();
572 $this->assertConnecting($state);
573 $state = $this->channel3->getConnectivityState();
574 $this->assertConnecting($state);
576 $this->channel1->close();
579 public function callbackFunc($context)
584 public function callbackFunc2($context)
586 return ["k1" => "v1"];
589 public function testPersistentChannelWithCallCredentials()
591 $creds = Grpc\ChannelCredentials::createSsl();
592 $callCreds = Grpc\CallCredentials::createFromPlugin(
593 [$this, 'callbackFunc']);
594 $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
597 // If a ChannelCredentials object is composed with a
598 // CallCredentials object, the underlying grpc channel will
599 // always be created new and NOT persisted.
600 $this->channel1 = new Grpc\Channel('localhost:50026',
603 "grpc_target_persist_bound" => 3,
605 $this->channel2 = new Grpc\Channel('localhost:50026',
607 $credsWithCallCreds]);
609 // try to connect on channel1
610 $state = $this->channel1->getConnectivityState(true);
611 $this->waitUntilNotIdle($this->channel1);
613 $state = $this->channel1->getConnectivityState();
614 $this->assertConnecting($state);
615 $state = $this->channel2->getConnectivityState();
616 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
618 $this->channel1->close();
619 $this->channel2->close();
622 public function testPersistentChannelWithDifferentCallCredentials()
624 $callCreds1 = Grpc\CallCredentials::createFromPlugin(
625 [$this, 'callbackFunc']);
626 $callCreds2 = Grpc\CallCredentials::createFromPlugin(
627 [$this, 'callbackFunc2']);
629 $creds1 = Grpc\ChannelCredentials::createSsl();
630 $creds2 = Grpc\ChannelCredentials::createComposite(
631 $creds1, $callCreds1);
632 $creds3 = Grpc\ChannelCredentials::createComposite(
633 $creds1, $callCreds2);
635 // Similar to the test above, anytime a ChannelCredentials
636 // object is composed with a CallCredentials object, the
637 // underlying grpc channel will always be separate and not
639 $this->channel1 = new Grpc\Channel('localhost:50027',
640 ["credentials" => $creds1,
641 "grpc_target_persist_bound" => 3,
643 $this->channel2 = new Grpc\Channel('localhost:50027',
644 ["credentials" => $creds2]);
645 $this->channel3 = new Grpc\Channel('localhost:50027',
646 ["credentials" => $creds3]);
648 // try to connect on channel1
649 $state = $this->channel1->getConnectivityState(true);
650 $this->waitUntilNotIdle($this->channel1);
652 $state = $this->channel1->getConnectivityState();
653 $this->assertConnecting($state);
654 $state = $this->channel2->getConnectivityState();
655 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
656 $state = $this->channel3->getConnectivityState();
657 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
659 $this->channel1->close();
660 $this->channel2->close();
661 $this->channel3->close();
664 public function testPersistentChannelForceNew()
666 $this->channel1 = new Grpc\Channel('localhost:50028', [
667 "grpc_target_persist_bound" => 2,
669 // even though all the channel params are the same, channel2
670 // has a new and different underlying channel
671 $this->channel2 = new Grpc\Channel('localhost:50028',
672 ["force_new" => true]);
674 // try to connect on channel1
675 $state = $this->channel1->getConnectivityState(true);
676 $this->waitUntilNotIdle($this->channel1);
678 $state = $this->channel1->getConnectivityState();
679 $this->assertConnecting($state);
680 $state = $this->channel2->getConnectivityState();
681 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
683 $this->channel1->close();
684 $this->channel2->close();
687 public function testPersistentChannelForceNewOldChannelIdle1()
690 $this->channel1 = new Grpc\Channel('localhost:50029', [
691 "grpc_target_persist_bound" => 2,
693 $this->channel2 = new Grpc\Channel('localhost:50029',
694 ["force_new" => true]);
695 // channel3 shares with channel1
696 $this->channel3 = new Grpc\Channel('localhost:50029', []);
698 // try to connect on channel2
699 $state = $this->channel2->getConnectivityState(true);
700 $this->waitUntilNotIdle($this->channel2);
701 $state = $this->channel1->getConnectivityState();
702 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
703 $state = $this->channel2->getConnectivityState();
704 $this->assertConnecting($state);
705 $state = $this->channel3->getConnectivityState();
706 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
708 $this->channel1->close();
709 $this->channel2->close();
712 public function testPersistentChannelForceNewOldChannelIdle2()
715 $this->channel1 = new Grpc\Channel('localhost:50032', [
716 "grpc_target_persist_bound" => 2,
718 $this->channel2 = new Grpc\Channel('localhost:50032', []);
720 // try to connect on channel2
721 $state = $this->channel1->getConnectivityState(true);
722 $this->waitUntilNotIdle($this->channel2);
723 $state = $this->channel1->getConnectivityState();
724 $this->assertConnecting($state);
725 $state = $this->channel2->getConnectivityState();
726 $this->assertConnecting($state);
728 $this->channel1->close();
729 $this->channel2->close();
732 public function testPersistentChannelForceNewOldChannelClose1()
735 $this->channel1 = new Grpc\Channel('localhost:50130', [
736 "grpc_target_persist_bound" => 2,
738 $this->channel2 = new Grpc\Channel('localhost:50130',
739 ["force_new" => true]);
740 // channel3 shares with channel1
741 $this->channel3 = new Grpc\Channel('localhost:50130', []);
743 $this->channel1->close();
745 $state = $this->channel2->getConnectivityState();
746 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
748 // channel3 is still usable. We need to exclude the possibility that in
749 // testPersistentChannelForceNewOldChannelClose2, the exception is thrown
750 // by channel1 and channel2.
751 $state = $this->channel3->getConnectivityState();
752 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
755 public function testPersistentChannelForceNewOldChannelClose2()
757 $this->expectException(\RuntimeException::class);
758 $this->channel1 = new Grpc\Channel('localhost:50230', [
759 "grpc_target_persist_bound" => 2,
761 $this->channel2 = new Grpc\Channel('localhost:50230',
762 ["force_new" => true]);
763 // channel3 shares with channel1
764 $this->channel3 = new Grpc\Channel('localhost:50230', []);
766 $this->channel1->close();
768 $state = $this->channel2->getConnectivityState();
769 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
771 // channel3 is still usable
772 $state = $this->channel3->getConnectivityState();
773 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
775 // channel 1 is closed
776 $this->channel1->getConnectivityState();
779 public function testPersistentChannelForceNewNewChannelClose()
782 $this->channel1 = new Grpc\Channel('localhost:50031', [
783 "grpc_target_persist_bound" => 2,
785 $this->channel2 = new Grpc\Channel('localhost:50031',
786 ["force_new" => true]);
787 $this->channel3 = new Grpc\Channel('localhost:50031', []);
789 $this->channel2->close();
791 $state = $this->channel1->getConnectivityState();
792 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
794 // can still connect on channel1
795 $state = $this->channel1->getConnectivityState(true);
796 $this->waitUntilNotIdle($this->channel1);
798 $state = $this->channel1->getConnectivityState();
799 $this->assertConnecting($state);
801 $this->channel1->close();