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 testGetConnectivityState()
49 $this->channel = new Grpc\Channel('localhost:50001',
50 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
51 $state = $this->channel->getConnectivityState();
52 $this->assertEquals(0, $state);
55 public function testGetConnectivityStateWithInt()
57 $this->channel = new Grpc\Channel('localhost:50002',
58 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
59 $state = $this->channel->getConnectivityState(123);
60 $this->assertEquals(0, $state);
63 public function testGetConnectivityStateWithString()
65 $this->channel = new Grpc\Channel('localhost:50003',
66 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
67 $state = $this->channel->getConnectivityState('hello');
68 $this->assertEquals(0, $state);
71 public function testGetConnectivityStateWithBool()
73 $this->channel = new Grpc\Channel('localhost:50004',
74 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
75 $state = $this->channel->getConnectivityState(true);
76 $this->assertEquals(0, $state);
79 public function testGetTarget()
81 $this->channel = new Grpc\Channel('localhost:50005',
82 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
83 $target = $this->channel->getTarget();
84 $this->assertTrue(is_string($target));
87 public function testWatchConnectivityState()
89 $this->channel = new Grpc\Channel('localhost:50006',
90 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
91 $now = Grpc\Timeval::now();
92 $deadline = $now->add(new Grpc\Timeval(100*1000)); // 100ms
93 // we act as if 'CONNECTING'(=1) was the last state
94 // we saw, so the default state of 'IDLE' should be delivered instantly
95 $state = $this->channel->watchConnectivityState(1, $deadline);
96 $this->assertTrue($state);
101 public function testClose()
103 $this->channel = new Grpc\Channel('localhost:50007',
104 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
105 $this->assertNotNull($this->channel);
106 $this->channel->close();
109 public function testInvalidConstructorWithNull()
111 $this->expectException(\InvalidArgumentException::class);
112 $this->channel = new Grpc\Channel();
113 $this->assertNull($this->channel);
116 public function testInvalidConstructorWith()
118 $this->expectException(\InvalidArgumentException::class);
119 $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
120 $this->assertNull($this->channel);
123 public function testInvalidCredentials()
125 $this->expectException(\InvalidArgumentException::class);
126 $this->channel = new Grpc\Channel('localhost:50009',
127 ['credentials' => new Grpc\Timeval(100)]);
130 public function testInvalidOptionsArray()
132 $this->expectException(\InvalidArgumentException::class);
133 $this->channel = new Grpc\Channel('localhost:50010',
137 public function testInvalidGetConnectivityStateWithArray()
139 $this->expectException(\InvalidArgumentException::class);
140 $this->channel = new Grpc\Channel('localhost:50011',
141 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
142 $this->channel->getConnectivityState([]);
145 public function testInvalidWatchConnectivityState()
147 $this->expectException(\InvalidArgumentException::class);
148 $this->channel = new Grpc\Channel('localhost:50012',
149 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
150 $this->channel->watchConnectivityState([]);
153 public function testInvalidWatchConnectivityState2()
155 $this->expectException(\InvalidArgumentException::class);
156 $this->channel = new Grpc\Channel('localhost:50013',
157 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
158 $this->channel->watchConnectivityState(1, 'hi');
162 public function assertConnecting($state) {
163 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
164 $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
167 public function waitUntilNotIdle($channel) {
168 for ($i = 0; $i < 10; $i++) {
169 $now = Grpc\Timeval::now();
170 $deadline = $now->add(new Grpc\Timeval(1000));
171 if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
176 $this->assertTrue(false);
179 public function testPersistentChannelSameHost()
181 $this->channel1 = new Grpc\Channel('localhost:50014', [
182 "grpc_target_persist_bound" => 3,
184 // the underlying grpc channel is the same by default
185 // when connecting to the same host
186 $this->channel2 = new Grpc\Channel('localhost:50014', []);
188 // both channels should be IDLE
189 $state = $this->channel1->getConnectivityState();
190 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
191 $state = $this->channel2->getConnectivityState();
192 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
194 // try to connect on channel1
195 $state = $this->channel1->getConnectivityState(true);
196 $this->waitUntilNotIdle($this->channel1);
198 // both channels should now be in the CONNECTING state
199 $state = $this->channel1->getConnectivityState();
200 $this->assertConnecting($state);
201 $state = $this->channel2->getConnectivityState();
202 $this->assertConnecting($state);
204 $this->channel1->close();
205 $this->channel2->close();
208 public function testPersistentChannelDifferentHost()
210 // two different underlying channels because different hostname
211 $this->channel1 = new Grpc\Channel('localhost:50015', [
212 "grpc_target_persist_bound" => 3,
214 $this->channel2 = new Grpc\Channel('localhost:50016', []);
216 // both channels should be IDLE
217 $state = $this->channel1->getConnectivityState();
218 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
219 $state = $this->channel2->getConnectivityState();
220 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
222 // try to connect on channel1
223 $state = $this->channel1->getConnectivityState(true);
224 $this->waitUntilNotIdle($this->channel1);
226 // channel1 should now be in the CONNECTING state
227 $state = $this->channel1->getConnectivityState();
228 $this->assertConnecting($state);
229 // channel2 should still be in the IDLE state
230 $state = $this->channel2->getConnectivityState();
231 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
233 $this->channel1->close();
234 $this->channel2->close();
237 public function testPersistentChannelSameArgs()
239 $this->channel1 = new Grpc\Channel('localhost:50017', [
240 "grpc_target_persist_bound" => 3,
243 $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
245 // try to connect on channel1
246 $state = $this->channel1->getConnectivityState(true);
247 $this->waitUntilNotIdle($this->channel1);
249 $state = $this->channel1->getConnectivityState();
250 $this->assertConnecting($state);
251 $state = $this->channel2->getConnectivityState();
252 $this->assertConnecting($state);
254 $this->channel1->close();
255 $this->channel2->close();
258 public function testPersistentChannelDifferentArgs()
260 $this->channel1 = new Grpc\Channel('localhost:50018', [
261 "grpc_target_persist_bound" => 3,
263 $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
265 // try to connect on channel1
266 $state = $this->channel1->getConnectivityState(true);
267 $this->waitUntilNotIdle($this->channel1);
269 $state = $this->channel1->getConnectivityState();
270 $this->assertConnecting($state);
271 $state = $this->channel2->getConnectivityState();
272 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
274 $this->channel1->close();
275 $this->channel2->close();
278 public function testPersistentChannelSameChannelCredentials()
280 $creds1 = Grpc\ChannelCredentials::createSsl();
281 $creds2 = Grpc\ChannelCredentials::createSsl();
283 $this->channel1 = new Grpc\Channel('localhost:50019',
284 ["credentials" => $creds1,
285 "grpc_target_persist_bound" => 3,
287 $this->channel2 = new Grpc\Channel('localhost:50019',
288 ["credentials" => $creds2]);
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->assertConnecting($state);
299 $this->channel1->close();
300 $this->channel2->close();
303 public function testPersistentChannelDifferentChannelCredentials()
305 $creds1 = Grpc\ChannelCredentials::createSsl();
306 $creds2 = Grpc\ChannelCredentials::createSsl(
307 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
309 $this->channel1 = new Grpc\Channel('localhost:50020',
310 ["credentials" => $creds1,
311 "grpc_target_persist_bound" => 3,
313 $this->channel2 = new Grpc\Channel('localhost:50020',
314 ["credentials" => $creds2]);
316 // try to connect on channel1
317 $state = $this->channel1->getConnectivityState(true);
318 $this->waitUntilNotIdle($this->channel1);
320 $state = $this->channel1->getConnectivityState();
321 $this->assertConnecting($state);
322 $state = $this->channel2->getConnectivityState();
323 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
325 $this->channel1->close();
326 $this->channel2->close();
329 public function testPersistentChannelSameChannelCredentialsRootCerts()
331 $creds1 = Grpc\ChannelCredentials::createSsl(
332 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
333 $creds2 = Grpc\ChannelCredentials::createSsl(
334 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
336 $this->channel1 = new Grpc\Channel('localhost:50021',
337 ["credentials" => $creds1,
338 "grpc_target_persist_bound" => 3,
340 $this->channel2 = new Grpc\Channel('localhost:50021',
341 ["credentials" => $creds2]);
343 // try to connect on channel1
344 $state = $this->channel1->getConnectivityState(true);
345 $this->waitUntilNotIdle($this->channel1);
347 $state = $this->channel1->getConnectivityState();
348 $this->assertConnecting($state);
349 $state = $this->channel2->getConnectivityState();
350 $this->assertConnecting($state);
352 $this->channel1->close();
353 $this->channel2->close();
356 public function testPersistentChannelDifferentSecureChannelCredentials()
358 $creds1 = Grpc\ChannelCredentials::createSsl();
359 $creds2 = Grpc\ChannelCredentials::createInsecure();
361 $this->channel1 = new Grpc\Channel('localhost:50022',
362 ["credentials" => $creds1,
363 "grpc_target_persist_bound" => 3,
365 $this->channel2 = new Grpc\Channel('localhost:50022',
366 ["credentials" => $creds2]);
368 // try to connect on channel1
369 $state = $this->channel1->getConnectivityState(true);
370 $this->waitUntilNotIdle($this->channel1);
372 $state = $this->channel1->getConnectivityState();
373 $this->assertConnecting($state);
374 $state = $this->channel2->getConnectivityState();
375 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
377 $this->channel1->close();
378 $this->channel2->close();
381 public function testPersistentChannelSharedChannelClose1()
383 // same underlying channel
384 $this->channel1 = new Grpc\Channel('localhost:50123', [
385 "grpc_target_persist_bound" => 3,
387 $this->channel2 = new Grpc\Channel('localhost:50123', []);
390 $this->channel1->close();
392 // channel2 can still be use. We need to exclude the possible that
393 // in testPersistentChannelSharedChannelClose2, the exception is thrown
395 $state = $this->channel2->getConnectivityState();
396 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
399 public function testPersistentChannelSharedChannelClose2()
401 $this->expectException(\RuntimeException::class);
402 // same underlying channel
403 $this->channel1 = new Grpc\Channel('localhost:50223', [
404 "grpc_target_persist_bound" => 3,
406 $this->channel2 = new Grpc\Channel('localhost:50223', []);
409 $this->channel1->close();
411 // channel2 can still be use
412 $state = $this->channel2->getConnectivityState();
413 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
415 // channel 1 is closed
416 $state = $this->channel1->getConnectivityState();
419 public function testPersistentChannelCreateAfterClose()
421 $this->channel1 = new Grpc\Channel('localhost:50024', [
422 "grpc_target_persist_bound" => 3,
425 $this->channel1->close();
427 $this->channel2 = new Grpc\Channel('localhost:50024', []);
428 $state = $this->channel2->getConnectivityState();
429 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
431 $this->channel2->close();
434 public function testPersistentChannelSharedMoreThanTwo()
436 $this->channel1 = new Grpc\Channel('localhost:50025', [
437 "grpc_target_persist_bound" => 3,
439 $this->channel2 = new Grpc\Channel('localhost:50025', []);
440 $this->channel3 = new Grpc\Channel('localhost:50025', []);
442 // try to connect on channel1
443 $state = $this->channel1->getConnectivityState(true);
444 $this->waitUntilNotIdle($this->channel1);
446 // all 3 channels should be in CONNECTING state
447 $state = $this->channel1->getConnectivityState();
448 $this->assertConnecting($state);
449 $state = $this->channel2->getConnectivityState();
450 $this->assertConnecting($state);
451 $state = $this->channel3->getConnectivityState();
452 $this->assertConnecting($state);
454 $this->channel1->close();
457 public function callbackFunc($context)
462 public function callbackFunc2($context)
464 return ["k1" => "v1"];
467 public function testPersistentChannelWithCallCredentials()
469 $creds = Grpc\ChannelCredentials::createSsl();
470 $callCreds = Grpc\CallCredentials::createFromPlugin(
471 [$this, 'callbackFunc']);
472 $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
475 // If a ChannelCredentials object is composed with a
476 // CallCredentials object, the underlying grpc channel will
477 // always be created new and NOT persisted.
478 $this->channel1 = new Grpc\Channel('localhost:50026',
481 "grpc_target_persist_bound" => 3,
483 $this->channel2 = new Grpc\Channel('localhost:50026',
485 $credsWithCallCreds]);
487 // try to connect on channel1
488 $state = $this->channel1->getConnectivityState(true);
489 $this->waitUntilNotIdle($this->channel1);
491 $state = $this->channel1->getConnectivityState();
492 $this->assertConnecting($state);
493 $state = $this->channel2->getConnectivityState();
494 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
496 $this->channel1->close();
497 $this->channel2->close();
500 public function testPersistentChannelWithDifferentCallCredentials()
502 $callCreds1 = Grpc\CallCredentials::createFromPlugin(
503 [$this, 'callbackFunc']);
504 $callCreds2 = Grpc\CallCredentials::createFromPlugin(
505 [$this, 'callbackFunc2']);
507 $creds1 = Grpc\ChannelCredentials::createSsl();
508 $creds2 = Grpc\ChannelCredentials::createComposite(
509 $creds1, $callCreds1);
510 $creds3 = Grpc\ChannelCredentials::createComposite(
511 $creds1, $callCreds2);
513 // Similar to the test above, anytime a ChannelCredentials
514 // object is composed with a CallCredentials object, the
515 // underlying grpc channel will always be separate and not
517 $this->channel1 = new Grpc\Channel('localhost:50027',
518 ["credentials" => $creds1,
519 "grpc_target_persist_bound" => 3,
521 $this->channel2 = new Grpc\Channel('localhost:50027',
522 ["credentials" => $creds2]);
523 $this->channel3 = new Grpc\Channel('localhost:50027',
524 ["credentials" => $creds3]);
526 // try to connect on channel1
527 $state = $this->channel1->getConnectivityState(true);
528 $this->waitUntilNotIdle($this->channel1);
530 $state = $this->channel1->getConnectivityState();
531 $this->assertConnecting($state);
532 $state = $this->channel2->getConnectivityState();
533 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
534 $state = $this->channel3->getConnectivityState();
535 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
537 $this->channel1->close();
538 $this->channel2->close();
539 $this->channel3->close();
542 public function testPersistentChannelForceNew()
544 $this->channel1 = new Grpc\Channel('localhost:50028', [
545 "grpc_target_persist_bound" => 2,
547 // even though all the channel params are the same, channel2
548 // has a new and different underlying channel
549 $this->channel2 = new Grpc\Channel('localhost:50028',
550 ["force_new" => true]);
552 // try to connect on channel1
553 $state = $this->channel1->getConnectivityState(true);
554 $this->waitUntilNotIdle($this->channel1);
556 $state = $this->channel1->getConnectivityState();
557 $this->assertConnecting($state);
558 $state = $this->channel2->getConnectivityState();
559 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
561 $this->channel1->close();
562 $this->channel2->close();
565 public function testPersistentChannelForceNewOldChannelIdle1()
568 $this->channel1 = new Grpc\Channel('localhost:50029', [
569 "grpc_target_persist_bound" => 2,
571 $this->channel2 = new Grpc\Channel('localhost:50029',
572 ["force_new" => true]);
573 // channel3 shares with channel1
574 $this->channel3 = new Grpc\Channel('localhost:50029', []);
576 // try to connect on channel2
577 $state = $this->channel2->getConnectivityState(true);
578 $this->waitUntilNotIdle($this->channel2);
579 $state = $this->channel1->getConnectivityState();
580 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
581 $state = $this->channel2->getConnectivityState();
582 $this->assertConnecting($state);
583 $state = $this->channel3->getConnectivityState();
584 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
586 $this->channel1->close();
587 $this->channel2->close();
590 public function testPersistentChannelForceNewOldChannelIdle2()
593 $this->channel1 = new Grpc\Channel('localhost:50032', [
594 "grpc_target_persist_bound" => 2,
596 $this->channel2 = new Grpc\Channel('localhost:50032', []);
598 // try to connect on channel2
599 $state = $this->channel1->getConnectivityState(true);
600 $this->waitUntilNotIdle($this->channel2);
601 $state = $this->channel1->getConnectivityState();
602 $this->assertConnecting($state);
603 $state = $this->channel2->getConnectivityState();
604 $this->assertConnecting($state);
606 $this->channel1->close();
607 $this->channel2->close();
610 public function testPersistentChannelForceNewOldChannelClose1()
613 $this->channel1 = new Grpc\Channel('localhost:50130', [
614 "grpc_target_persist_bound" => 2,
616 $this->channel2 = new Grpc\Channel('localhost:50130',
617 ["force_new" => true]);
618 // channel3 shares with channel1
619 $this->channel3 = new Grpc\Channel('localhost:50130', []);
621 $this->channel1->close();
623 $state = $this->channel2->getConnectivityState();
624 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
626 // channel3 is still usable. We need to exclude the possibility that in
627 // testPersistentChannelForceNewOldChannelClose2, the exception is thrown
628 // by channel1 and channel2.
629 $state = $this->channel3->getConnectivityState();
630 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
633 public function testPersistentChannelForceNewOldChannelClose2()
635 $this->expectException(\RuntimeException::class);
636 $this->channel1 = new Grpc\Channel('localhost:50230', [
637 "grpc_target_persist_bound" => 2,
639 $this->channel2 = new Grpc\Channel('localhost:50230',
640 ["force_new" => true]);
641 // channel3 shares with channel1
642 $this->channel3 = new Grpc\Channel('localhost:50230', []);
644 $this->channel1->close();
646 $state = $this->channel2->getConnectivityState();
647 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
649 // channel3 is still usable
650 $state = $this->channel3->getConnectivityState();
651 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
653 // channel 1 is closed
654 $this->channel1->getConnectivityState();
657 public function testPersistentChannelForceNewNewChannelClose()
660 $this->channel1 = new Grpc\Channel('localhost:50031', [
661 "grpc_target_persist_bound" => 2,
663 $this->channel2 = new Grpc\Channel('localhost:50031',
664 ["force_new" => true]);
665 $this->channel3 = new Grpc\Channel('localhost:50031', []);
667 $this->channel2->close();
669 $state = $this->channel1->getConnectivityState();
670 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
672 // can still connect on channel1
673 $state = $this->channel1->getConnectivityState(true);
674 $this->waitUntilNotIdle($this->channel1);
676 $state = $this->channel1->getConnectivityState();
677 $this->assertConnecting($state);
679 $this->channel1->close();