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 new Grpc\Channel('localhost:50033',
43 ['credentials' => \Grpc\ChannelCredentials::createSsl()]);
46 public function testGetConnectivityState()
48 $this->channel = new Grpc\Channel('localhost:50001',
49 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
50 $state = $this->channel->getConnectivityState();
51 $this->assertEquals(0, $state);
54 public function testGetConnectivityStateWithInt()
56 $this->channel = new Grpc\Channel('localhost:50002',
57 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
58 $state = $this->channel->getConnectivityState(123);
59 $this->assertEquals(0, $state);
62 public function testGetConnectivityStateWithString()
64 $this->channel = new Grpc\Channel('localhost:50003',
65 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
66 $state = $this->channel->getConnectivityState('hello');
67 $this->assertEquals(0, $state);
70 public function testGetConnectivityStateWithBool()
72 $this->channel = new Grpc\Channel('localhost:50004',
73 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
74 $state = $this->channel->getConnectivityState(true);
75 $this->assertEquals(0, $state);
78 public function testGetTarget()
80 $this->channel = new Grpc\Channel('localhost:50005',
81 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
82 $target = $this->channel->getTarget();
83 $this->assertTrue(is_string($target));
86 public function testWatchConnectivityState()
88 $this->channel = new Grpc\Channel('localhost:50006',
89 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
90 $now = Grpc\Timeval::now();
91 $deadline = $now->add(new Grpc\Timeval(100*1000)); // 100ms
92 // we act as if 'CONNECTING'(=1) was the last state
93 // we saw, so the default state of 'IDLE' should be delivered instantly
94 $state = $this->channel->watchConnectivityState(1, $deadline);
95 $this->assertTrue($state);
100 public function testClose()
102 $this->channel = new Grpc\Channel('localhost:50007',
103 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
104 $this->assertNotNull($this->channel);
105 $this->channel->close();
109 * @expectedException InvalidArgumentException
111 public function testInvalidConstructorWithNull()
113 $this->channel = new Grpc\Channel();
114 $this->assertNull($this->channel);
118 * @expectedException InvalidArgumentException
120 public function testInvalidConstructorWith()
122 $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
123 $this->assertNull($this->channel);
127 * @expectedException InvalidArgumentException
129 public function testInvalidCredentials()
131 $this->channel = new Grpc\Channel('localhost:50009',
132 ['credentials' => new Grpc\Timeval(100)]);
136 * @expectedException InvalidArgumentException
138 public function testInvalidOptionsArray()
140 $this->channel = new Grpc\Channel('localhost:50010',
145 * @expectedException InvalidArgumentException
147 public function testInvalidGetConnectivityStateWithArray()
149 $this->channel = new Grpc\Channel('localhost:50011',
150 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
151 $this->channel->getConnectivityState([]);
155 * @expectedException InvalidArgumentException
157 public function testInvalidWatchConnectivityState()
159 $this->channel = new Grpc\Channel('localhost:50012',
160 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
161 $this->channel->watchConnectivityState([]);
165 * @expectedException InvalidArgumentException
167 public function testInvalidWatchConnectivityState2()
169 $this->channel = new Grpc\Channel('localhost:50013',
170 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
171 $this->channel->watchConnectivityState(1, 'hi');
175 public function assertConnecting($state) {
176 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
177 $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
180 public function waitUntilNotIdle($channel) {
181 for ($i = 0; $i < 10; $i++) {
182 $now = Grpc\Timeval::now();
183 $deadline = $now->add(new Grpc\Timeval(1000));
184 if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
189 $this->assertTrue(false);
192 public function testPersistentChannelSameHost()
194 $this->channel1 = new Grpc\Channel('localhost:50014', [
195 "grpc_target_persist_bound" => 3,
197 // the underlying grpc channel is the same by default
198 // when connecting to the same host
199 $this->channel2 = new Grpc\Channel('localhost:50014', []);
201 // both channels should be IDLE
202 $state = $this->channel1->getConnectivityState();
203 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
204 $state = $this->channel2->getConnectivityState();
205 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
207 // try to connect on channel1
208 $state = $this->channel1->getConnectivityState(true);
209 $this->waitUntilNotIdle($this->channel1);
211 // both channels should now be in the CONNECTING state
212 $state = $this->channel1->getConnectivityState();
213 $this->assertConnecting($state);
214 $state = $this->channel2->getConnectivityState();
215 $this->assertConnecting($state);
217 $this->channel1->close();
218 $this->channel2->close();
221 public function testPersistentChannelDifferentHost()
223 // two different underlying channels because different hostname
224 $this->channel1 = new Grpc\Channel('localhost:50015', [
225 "grpc_target_persist_bound" => 3,
227 $this->channel2 = new Grpc\Channel('localhost:50016', []);
229 // both channels should be IDLE
230 $state = $this->channel1->getConnectivityState();
231 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
232 $state = $this->channel2->getConnectivityState();
233 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
235 // try to connect on channel1
236 $state = $this->channel1->getConnectivityState(true);
237 $this->waitUntilNotIdle($this->channel1);
239 // channel1 should now be in the CONNECTING state
240 $state = $this->channel1->getConnectivityState();
241 $this->assertConnecting($state);
242 // channel2 should still be in the IDLE state
243 $state = $this->channel2->getConnectivityState();
244 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
246 $this->channel1->close();
247 $this->channel2->close();
250 public function testPersistentChannelSameArgs()
252 $this->channel1 = new Grpc\Channel('localhost:50017', [
253 "grpc_target_persist_bound" => 3,
256 $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
258 // try to connect on channel1
259 $state = $this->channel1->getConnectivityState(true);
260 $this->waitUntilNotIdle($this->channel1);
262 $state = $this->channel1->getConnectivityState();
263 $this->assertConnecting($state);
264 $state = $this->channel2->getConnectivityState();
265 $this->assertConnecting($state);
267 $this->channel1->close();
268 $this->channel2->close();
271 public function testPersistentChannelDifferentArgs()
273 $this->channel1 = new Grpc\Channel('localhost:50018', [
274 "grpc_target_persist_bound" => 3,
276 $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
278 // try to connect on channel1
279 $state = $this->channel1->getConnectivityState(true);
280 $this->waitUntilNotIdle($this->channel1);
282 $state = $this->channel1->getConnectivityState();
283 $this->assertConnecting($state);
284 $state = $this->channel2->getConnectivityState();
285 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
287 $this->channel1->close();
288 $this->channel2->close();
291 public function testPersistentChannelSameChannelCredentials()
293 $creds1 = Grpc\ChannelCredentials::createSsl();
294 $creds2 = Grpc\ChannelCredentials::createSsl();
296 $this->channel1 = new Grpc\Channel('localhost:50019',
297 ["credentials" => $creds1,
298 "grpc_target_persist_bound" => 3,
300 $this->channel2 = new Grpc\Channel('localhost:50019',
301 ["credentials" => $creds2]);
303 // try to connect on channel1
304 $state = $this->channel1->getConnectivityState(true);
305 $this->waitUntilNotIdle($this->channel1);
307 $state = $this->channel1->getConnectivityState();
308 $this->assertConnecting($state);
309 $state = $this->channel2->getConnectivityState();
310 $this->assertConnecting($state);
312 $this->channel1->close();
313 $this->channel2->close();
316 public function testPersistentChannelDifferentChannelCredentials()
318 $creds1 = Grpc\ChannelCredentials::createSsl();
319 $creds2 = Grpc\ChannelCredentials::createSsl(
320 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
322 $this->channel1 = new Grpc\Channel('localhost:50020',
323 ["credentials" => $creds1,
324 "grpc_target_persist_bound" => 3,
326 $this->channel2 = new Grpc\Channel('localhost:50020',
327 ["credentials" => $creds2]);
329 // try to connect on channel1
330 $state = $this->channel1->getConnectivityState(true);
331 $this->waitUntilNotIdle($this->channel1);
333 $state = $this->channel1->getConnectivityState();
334 $this->assertConnecting($state);
335 $state = $this->channel2->getConnectivityState();
336 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
338 $this->channel1->close();
339 $this->channel2->close();
342 public function testPersistentChannelSameChannelCredentialsRootCerts()
344 $creds1 = Grpc\ChannelCredentials::createSsl(
345 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
346 $creds2 = Grpc\ChannelCredentials::createSsl(
347 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
349 $this->channel1 = new Grpc\Channel('localhost:50021',
350 ["credentials" => $creds1,
351 "grpc_target_persist_bound" => 3,
353 $this->channel2 = new Grpc\Channel('localhost:50021',
354 ["credentials" => $creds2]);
356 // try to connect on channel1
357 $state = $this->channel1->getConnectivityState(true);
358 $this->waitUntilNotIdle($this->channel1);
360 $state = $this->channel1->getConnectivityState();
361 $this->assertConnecting($state);
362 $state = $this->channel2->getConnectivityState();
363 $this->assertConnecting($state);
365 $this->channel1->close();
366 $this->channel2->close();
369 public function testPersistentChannelDifferentSecureChannelCredentials()
371 $creds1 = Grpc\ChannelCredentials::createSsl();
372 $creds2 = Grpc\ChannelCredentials::createInsecure();
374 $this->channel1 = new Grpc\Channel('localhost:50022',
375 ["credentials" => $creds1,
376 "grpc_target_persist_bound" => 3,
378 $this->channel2 = new Grpc\Channel('localhost:50022',
379 ["credentials" => $creds2]);
381 // try to connect on channel1
382 $state = $this->channel1->getConnectivityState(true);
383 $this->waitUntilNotIdle($this->channel1);
385 $state = $this->channel1->getConnectivityState();
386 $this->assertConnecting($state);
387 $state = $this->channel2->getConnectivityState();
388 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
390 $this->channel1->close();
391 $this->channel2->close();
394 public function testPersistentChannelSharedChannelClose1()
396 // same underlying channel
397 $this->channel1 = new Grpc\Channel('localhost:50123', [
398 "grpc_target_persist_bound" => 3,
400 $this->channel2 = new Grpc\Channel('localhost:50123', []);
403 $this->channel1->close();
405 // channel2 can still be use. We need to exclude the possible that
406 // in testPersistentChannelSharedChannelClose2, the exception is thrown
408 $state = $this->channel2->getConnectivityState();
409 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
413 * @expectedException RuntimeException
415 public function testPersistentChannelSharedChannelClose2()
417 // same underlying channel
418 $this->channel1 = new Grpc\Channel('localhost:50223', [
419 "grpc_target_persist_bound" => 3,
421 $this->channel2 = new Grpc\Channel('localhost:50223', []);
424 $this->channel1->close();
426 // channel2 can still be use
427 $state = $this->channel2->getConnectivityState();
428 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
430 // channel 1 is closed
431 $state = $this->channel1->getConnectivityState();
434 public function testPersistentChannelCreateAfterClose()
436 $this->channel1 = new Grpc\Channel('localhost:50024', [
437 "grpc_target_persist_bound" => 3,
440 $this->channel1->close();
442 $this->channel2 = new Grpc\Channel('localhost:50024', []);
443 $state = $this->channel2->getConnectivityState();
444 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
446 $this->channel2->close();
449 public function testPersistentChannelSharedMoreThanTwo()
451 $this->channel1 = new Grpc\Channel('localhost:50025', [
452 "grpc_target_persist_bound" => 3,
454 $this->channel2 = new Grpc\Channel('localhost:50025', []);
455 $this->channel3 = new Grpc\Channel('localhost:50025', []);
457 // try to connect on channel1
458 $state = $this->channel1->getConnectivityState(true);
459 $this->waitUntilNotIdle($this->channel1);
461 // all 3 channels should be in CONNECTING state
462 $state = $this->channel1->getConnectivityState();
463 $this->assertConnecting($state);
464 $state = $this->channel2->getConnectivityState();
465 $this->assertConnecting($state);
466 $state = $this->channel3->getConnectivityState();
467 $this->assertConnecting($state);
469 $this->channel1->close();
472 public function callbackFunc($context)
477 public function callbackFunc2($context)
479 return ["k1" => "v1"];
482 public function testPersistentChannelWithCallCredentials()
484 $creds = Grpc\ChannelCredentials::createSsl();
485 $callCreds = Grpc\CallCredentials::createFromPlugin(
486 [$this, 'callbackFunc']);
487 $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
490 // If a ChannelCredentials object is composed with a
491 // CallCredentials object, the underlying grpc channel will
492 // always be created new and NOT persisted.
493 $this->channel1 = new Grpc\Channel('localhost:50026',
496 "grpc_target_persist_bound" => 3,
498 $this->channel2 = new Grpc\Channel('localhost:50026',
500 $credsWithCallCreds]);
502 // try to connect on channel1
503 $state = $this->channel1->getConnectivityState(true);
504 $this->waitUntilNotIdle($this->channel1);
506 $state = $this->channel1->getConnectivityState();
507 $this->assertConnecting($state);
508 $state = $this->channel2->getConnectivityState();
509 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
511 $this->channel1->close();
512 $this->channel2->close();
515 public function testPersistentChannelWithDifferentCallCredentials()
517 $callCreds1 = Grpc\CallCredentials::createFromPlugin(
518 [$this, 'callbackFunc']);
519 $callCreds2 = Grpc\CallCredentials::createFromPlugin(
520 [$this, 'callbackFunc2']);
522 $creds1 = Grpc\ChannelCredentials::createSsl();
523 $creds2 = Grpc\ChannelCredentials::createComposite(
524 $creds1, $callCreds1);
525 $creds3 = Grpc\ChannelCredentials::createComposite(
526 $creds1, $callCreds2);
528 // Similar to the test above, anytime a ChannelCredentials
529 // object is composed with a CallCredentials object, the
530 // underlying grpc channel will always be separate and not
532 $this->channel1 = new Grpc\Channel('localhost:50027',
533 ["credentials" => $creds1,
534 "grpc_target_persist_bound" => 3,
536 $this->channel2 = new Grpc\Channel('localhost:50027',
537 ["credentials" => $creds2]);
538 $this->channel3 = new Grpc\Channel('localhost:50027',
539 ["credentials" => $creds3]);
541 // try to connect on channel1
542 $state = $this->channel1->getConnectivityState(true);
543 $this->waitUntilNotIdle($this->channel1);
545 $state = $this->channel1->getConnectivityState();
546 $this->assertConnecting($state);
547 $state = $this->channel2->getConnectivityState();
548 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
549 $state = $this->channel3->getConnectivityState();
550 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
552 $this->channel1->close();
553 $this->channel2->close();
554 $this->channel3->close();
557 public function testPersistentChannelForceNew()
559 $this->channel1 = new Grpc\Channel('localhost:50028', [
560 "grpc_target_persist_bound" => 2,
562 // even though all the channel params are the same, channel2
563 // has a new and different underlying channel
564 $this->channel2 = new Grpc\Channel('localhost:50028',
565 ["force_new" => true]);
567 // try to connect on channel1
568 $state = $this->channel1->getConnectivityState(true);
569 $this->waitUntilNotIdle($this->channel1);
571 $state = $this->channel1->getConnectivityState();
572 $this->assertConnecting($state);
573 $state = $this->channel2->getConnectivityState();
574 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
576 $this->channel1->close();
577 $this->channel2->close();
580 public function testPersistentChannelForceNewOldChannelIdle1()
583 $this->channel1 = new Grpc\Channel('localhost:50029', [
584 "grpc_target_persist_bound" => 2,
586 $this->channel2 = new Grpc\Channel('localhost:50029',
587 ["force_new" => true]);
588 // channel3 shares with channel1
589 $this->channel3 = new Grpc\Channel('localhost:50029', []);
591 // try to connect on channel2
592 $state = $this->channel2->getConnectivityState(true);
593 $this->waitUntilNotIdle($this->channel2);
594 $state = $this->channel1->getConnectivityState();
595 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
596 $state = $this->channel2->getConnectivityState();
597 $this->assertConnecting($state);
598 $state = $this->channel3->getConnectivityState();
599 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
601 $this->channel1->close();
602 $this->channel2->close();
605 public function testPersistentChannelForceNewOldChannelIdle2()
608 $this->channel1 = new Grpc\Channel('localhost:50032', [
609 "grpc_target_persist_bound" => 2,
611 $this->channel2 = new Grpc\Channel('localhost:50032', []);
613 // try to connect on channel2
614 $state = $this->channel1->getConnectivityState(true);
615 $this->waitUntilNotIdle($this->channel2);
616 $state = $this->channel1->getConnectivityState();
617 $this->assertConnecting($state);
618 $state = $this->channel2->getConnectivityState();
619 $this->assertConnecting($state);
621 $this->channel1->close();
622 $this->channel2->close();
625 public function testPersistentChannelForceNewOldChannelClose1()
628 $this->channel1 = new Grpc\Channel('localhost:50130', [
629 "grpc_target_persist_bound" => 2,
631 $this->channel2 = new Grpc\Channel('localhost:50130',
632 ["force_new" => true]);
633 // channel3 shares with channel1
634 $this->channel3 = new Grpc\Channel('localhost:50130', []);
636 $this->channel1->close();
638 $state = $this->channel2->getConnectivityState();
639 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
641 // channel3 is still usable. We need to exclude the possibility that in
642 // testPersistentChannelForceNewOldChannelClose2, the exception is thrown
643 // by channel1 and channel2.
644 $state = $this->channel3->getConnectivityState();
645 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
649 * @expectedException RuntimeException
651 public function testPersistentChannelForceNewOldChannelClose2()
654 $this->channel1 = new Grpc\Channel('localhost:50230', [
655 "grpc_target_persist_bound" => 2,
657 $this->channel2 = new Grpc\Channel('localhost:50230',
658 ["force_new" => true]);
659 // channel3 shares with channel1
660 $this->channel3 = new Grpc\Channel('localhost:50230', []);
662 $this->channel1->close();
664 $state = $this->channel2->getConnectivityState();
665 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
667 // channel3 is still usable
668 $state = $this->channel3->getConnectivityState();
669 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
671 // channel 1 is closed
672 $this->channel1->getConnectivityState();
675 public function testPersistentChannelForceNewNewChannelClose()
678 $this->channel1 = new Grpc\Channel('localhost:50031', [
679 "grpc_target_persist_bound" => 2,
681 $this->channel2 = new Grpc\Channel('localhost:50031',
682 ["force_new" => true]);
683 $this->channel3 = new Grpc\Channel('localhost:50031', []);
685 $this->channel2->close();
687 $state = $this->channel1->getConnectivityState();
688 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
690 // can still connect on channel1
691 $state = $this->channel1->getConnectivityState(true);
692 $this->waitUntilNotIdle($this->channel1);
694 $state = $this->channel1->getConnectivityState();
695 $this->assertConnecting($state);
697 $this->channel1->close();