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()
26 public function tearDown()
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 testGetConnectivityState()
42 $this->channel = new Grpc\Channel('localhost:50001',
43 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
44 $state = $this->channel->getConnectivityState();
45 $this->assertEquals(0, $state);
48 public function testGetConnectivityStateWithInt()
50 $this->channel = new Grpc\Channel('localhost:50002',
51 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
52 $state = $this->channel->getConnectivityState(123);
53 $this->assertEquals(0, $state);
56 public function testGetConnectivityStateWithString()
58 $this->channel = new Grpc\Channel('localhost:50003',
59 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
60 $state = $this->channel->getConnectivityState('hello');
61 $this->assertEquals(0, $state);
64 public function testGetConnectivityStateWithBool()
66 $this->channel = new Grpc\Channel('localhost:50004',
67 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
68 $state = $this->channel->getConnectivityState(true);
69 $this->assertEquals(0, $state);
72 public function testGetTarget()
74 $this->channel = new Grpc\Channel('localhost:50005',
75 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
76 $target = $this->channel->getTarget();
77 $this->assertTrue(is_string($target));
80 public function testWatchConnectivityState()
82 $this->channel = new Grpc\Channel('localhost:50006',
83 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
84 $now = Grpc\Timeval::now();
85 $deadline = $now->add(new Grpc\Timeval(100*1000)); // 100ms
86 // we act as if 'CONNECTING'(=1) was the last state
87 // we saw, so the default state of 'IDLE' should be delivered instantly
88 $state = $this->channel->watchConnectivityState(1, $deadline);
89 $this->assertTrue($state);
94 public function testClose()
96 $this->channel = new Grpc\Channel('localhost:50007',
97 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
98 $this->assertNotNull($this->channel);
99 $this->channel->close();
103 * @expectedException InvalidArgumentException
105 public function testInvalidConstructorWithNull()
107 $this->channel = new Grpc\Channel();
108 $this->assertNull($this->channel);
112 * @expectedException InvalidArgumentException
114 public function testInvalidConstructorWith()
116 $this->channel = new Grpc\Channel('localhost:50008', 'invalid');
117 $this->assertNull($this->channel);
121 * @expectedException InvalidArgumentException
123 public function testInvalidCredentials()
125 $this->channel = new Grpc\Channel('localhost:50009',
126 ['credentials' => new Grpc\Timeval(100)]);
130 * @expectedException InvalidArgumentException
132 public function testInvalidOptionsArray()
134 $this->channel = new Grpc\Channel('localhost:50010',
139 * @expectedException InvalidArgumentException
141 public function testInvalidGetConnectivityStateWithArray()
143 $this->channel = new Grpc\Channel('localhost:50011',
144 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
145 $this->channel->getConnectivityState([]);
149 * @expectedException InvalidArgumentException
151 public function testInvalidWatchConnectivityState()
153 $this->channel = new Grpc\Channel('localhost:50012',
154 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
155 $this->channel->watchConnectivityState([]);
159 * @expectedException InvalidArgumentException
161 public function testInvalidWatchConnectivityState2()
163 $this->channel = new Grpc\Channel('localhost:50013',
164 ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
165 $this->channel->watchConnectivityState(1, 'hi');
169 public function assertConnecting($state) {
170 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING ||
171 $state == GRPC\CHANNEL_TRANSIENT_FAILURE);
174 public function waitUntilNotIdle($channel) {
175 for ($i = 0; $i < 10; $i++) {
176 $now = Grpc\Timeval::now();
177 $deadline = $now->add(new Grpc\Timeval(1000));
178 if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE,
183 $this->assertTrue(false);
186 public function testPersistentChannelSameHost()
188 $this->channel1 = new Grpc\Channel('localhost:50014', [
189 "grpc_target_persist_bound" => 3,
191 // the underlying grpc channel is the same by default
192 // when connecting to the same host
193 $this->channel2 = new Grpc\Channel('localhost:50014', []);
195 // both channels should be IDLE
196 $state = $this->channel1->getConnectivityState();
197 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
198 $state = $this->channel2->getConnectivityState();
199 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
201 // try to connect on channel1
202 $state = $this->channel1->getConnectivityState(true);
203 $this->waitUntilNotIdle($this->channel1);
205 // both channels should now be in the CONNECTING state
206 $state = $this->channel1->getConnectivityState();
207 $this->assertConnecting($state);
208 $state = $this->channel2->getConnectivityState();
209 $this->assertConnecting($state);
211 $this->channel1->close();
212 $this->channel2->close();
215 public function testPersistentChannelDifferentHost()
217 // two different underlying channels because different hostname
218 $this->channel1 = new Grpc\Channel('localhost:50015', [
219 "grpc_target_persist_bound" => 3,
221 $this->channel2 = new Grpc\Channel('localhost:50016', []);
223 // both channels should be IDLE
224 $state = $this->channel1->getConnectivityState();
225 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
226 $state = $this->channel2->getConnectivityState();
227 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
229 // try to connect on channel1
230 $state = $this->channel1->getConnectivityState(true);
231 $this->waitUntilNotIdle($this->channel1);
233 // channel1 should now be in the CONNECTING state
234 $state = $this->channel1->getConnectivityState();
235 $this->assertConnecting($state);
236 // channel2 should still be in the IDLE state
237 $state = $this->channel2->getConnectivityState();
238 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
240 $this->channel1->close();
241 $this->channel2->close();
244 public function testPersistentChannelSameArgs()
246 $this->channel1 = new Grpc\Channel('localhost:50017', [
247 "grpc_target_persist_bound" => 3,
250 $this->channel2 = new Grpc\Channel('localhost:50017', ["abc" => "def"]);
252 // try to connect on channel1
253 $state = $this->channel1->getConnectivityState(true);
254 $this->waitUntilNotIdle($this->channel1);
256 $state = $this->channel1->getConnectivityState();
257 $this->assertConnecting($state);
258 $state = $this->channel2->getConnectivityState();
259 $this->assertConnecting($state);
261 $this->channel1->close();
262 $this->channel2->close();
265 public function testPersistentChannelDifferentArgs()
267 $this->channel1 = new Grpc\Channel('localhost:50018', [
268 "grpc_target_persist_bound" => 3,
270 $this->channel2 = new Grpc\Channel('localhost:50018', ["abc" => "def"]);
272 // try to connect on channel1
273 $state = $this->channel1->getConnectivityState(true);
274 $this->waitUntilNotIdle($this->channel1);
276 $state = $this->channel1->getConnectivityState();
277 $this->assertConnecting($state);
278 $state = $this->channel2->getConnectivityState();
279 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
281 $this->channel1->close();
282 $this->channel2->close();
285 public function testPersistentChannelSameChannelCredentials()
287 $creds1 = Grpc\ChannelCredentials::createSsl();
288 $creds2 = Grpc\ChannelCredentials::createSsl();
290 $this->channel1 = new Grpc\Channel('localhost:50019',
291 ["credentials" => $creds1,
292 "grpc_target_persist_bound" => 3,
294 $this->channel2 = new Grpc\Channel('localhost:50019',
295 ["credentials" => $creds2]);
297 // try to connect on channel1
298 $state = $this->channel1->getConnectivityState(true);
299 $this->waitUntilNotIdle($this->channel1);
301 $state = $this->channel1->getConnectivityState();
302 $this->assertConnecting($state);
303 $state = $this->channel2->getConnectivityState();
304 $this->assertConnecting($state);
306 $this->channel1->close();
307 $this->channel2->close();
310 public function testPersistentChannelDifferentChannelCredentials()
312 $creds1 = Grpc\ChannelCredentials::createSsl();
313 $creds2 = Grpc\ChannelCredentials::createSsl(
314 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
316 $this->channel1 = new Grpc\Channel('localhost:50020',
317 ["credentials" => $creds1,
318 "grpc_target_persist_bound" => 3,
320 $this->channel2 = new Grpc\Channel('localhost:50020',
321 ["credentials" => $creds2]);
323 // try to connect on channel1
324 $state = $this->channel1->getConnectivityState(true);
325 $this->waitUntilNotIdle($this->channel1);
327 $state = $this->channel1->getConnectivityState();
328 $this->assertConnecting($state);
329 $state = $this->channel2->getConnectivityState();
330 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
332 $this->channel1->close();
333 $this->channel2->close();
336 public function testPersistentChannelSameChannelCredentialsRootCerts()
338 $creds1 = Grpc\ChannelCredentials::createSsl(
339 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
340 $creds2 = Grpc\ChannelCredentials::createSsl(
341 file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
343 $this->channel1 = new Grpc\Channel('localhost:50021',
344 ["credentials" => $creds1,
345 "grpc_target_persist_bound" => 3,
347 $this->channel2 = new Grpc\Channel('localhost:50021',
348 ["credentials" => $creds2]);
350 // try to connect on channel1
351 $state = $this->channel1->getConnectivityState(true);
352 $this->waitUntilNotIdle($this->channel1);
354 $state = $this->channel1->getConnectivityState();
355 $this->assertConnecting($state);
356 $state = $this->channel2->getConnectivityState();
357 $this->assertConnecting($state);
359 $this->channel1->close();
360 $this->channel2->close();
363 public function testPersistentChannelDifferentSecureChannelCredentials()
365 $creds1 = Grpc\ChannelCredentials::createSsl();
366 $creds2 = Grpc\ChannelCredentials::createInsecure();
368 $this->channel1 = new Grpc\Channel('localhost:50022',
369 ["credentials" => $creds1,
370 "grpc_target_persist_bound" => 3,
372 $this->channel2 = new Grpc\Channel('localhost:50022',
373 ["credentials" => $creds2]);
375 // try to connect on channel1
376 $state = $this->channel1->getConnectivityState(true);
377 $this->waitUntilNotIdle($this->channel1);
379 $state = $this->channel1->getConnectivityState();
380 $this->assertConnecting($state);
381 $state = $this->channel2->getConnectivityState();
382 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
384 $this->channel1->close();
385 $this->channel2->close();
388 public function testPersistentChannelSharedChannelClose1()
390 // same underlying channel
391 $this->channel1 = new Grpc\Channel('localhost:50123', [
392 "grpc_target_persist_bound" => 3,
394 $this->channel2 = new Grpc\Channel('localhost:50123', []);
397 $this->channel1->close();
399 // channel2 can still be use. We need to exclude the possible that
400 // in testPersistentChannelSharedChannelClose2, the exception is thrown
402 $state = $this->channel2->getConnectivityState();
403 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
407 * @expectedException RuntimeException
409 public function testPersistentChannelSharedChannelClose2()
411 // same underlying channel
412 $this->channel1 = new Grpc\Channel('localhost:50223', [
413 "grpc_target_persist_bound" => 3,
415 $this->channel2 = new Grpc\Channel('localhost:50223', []);
418 $this->channel1->close();
420 // channel2 can still be use
421 $state = $this->channel2->getConnectivityState();
422 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
424 // channel 1 is closed
425 $state = $this->channel1->getConnectivityState();
428 public function testPersistentChannelCreateAfterClose()
430 $this->channel1 = new Grpc\Channel('localhost:50024', [
431 "grpc_target_persist_bound" => 3,
434 $this->channel1->close();
436 $this->channel2 = new Grpc\Channel('localhost:50024', []);
437 $state = $this->channel2->getConnectivityState();
438 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
440 $this->channel2->close();
443 public function testPersistentChannelSharedMoreThanTwo()
445 $this->channel1 = new Grpc\Channel('localhost:50025', [
446 "grpc_target_persist_bound" => 3,
448 $this->channel2 = new Grpc\Channel('localhost:50025', []);
449 $this->channel3 = new Grpc\Channel('localhost:50025', []);
451 // try to connect on channel1
452 $state = $this->channel1->getConnectivityState(true);
453 $this->waitUntilNotIdle($this->channel1);
455 // all 3 channels should be in CONNECTING state
456 $state = $this->channel1->getConnectivityState();
457 $this->assertConnecting($state);
458 $state = $this->channel2->getConnectivityState();
459 $this->assertConnecting($state);
460 $state = $this->channel3->getConnectivityState();
461 $this->assertConnecting($state);
463 $this->channel1->close();
466 public function callbackFunc($context)
471 public function callbackFunc2($context)
473 return ["k1" => "v1"];
476 public function testPersistentChannelWithCallCredentials()
478 $creds = Grpc\ChannelCredentials::createSsl();
479 $callCreds = Grpc\CallCredentials::createFromPlugin(
480 [$this, 'callbackFunc']);
481 $credsWithCallCreds = Grpc\ChannelCredentials::createComposite(
484 // If a ChannelCredentials object is composed with a
485 // CallCredentials object, the underlying grpc channel will
486 // always be created new and NOT persisted.
487 $this->channel1 = new Grpc\Channel('localhost:50026',
490 "grpc_target_persist_bound" => 3,
492 $this->channel2 = new Grpc\Channel('localhost:50026',
494 $credsWithCallCreds]);
496 // try to connect on channel1
497 $state = $this->channel1->getConnectivityState(true);
498 $this->waitUntilNotIdle($this->channel1);
500 $state = $this->channel1->getConnectivityState();
501 $this->assertConnecting($state);
502 $state = $this->channel2->getConnectivityState();
503 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
505 $this->channel1->close();
506 $this->channel2->close();
509 public function testPersistentChannelWithDifferentCallCredentials()
511 $callCreds1 = Grpc\CallCredentials::createFromPlugin(
512 [$this, 'callbackFunc']);
513 $callCreds2 = Grpc\CallCredentials::createFromPlugin(
514 [$this, 'callbackFunc2']);
516 $creds1 = Grpc\ChannelCredentials::createSsl();
517 $creds2 = Grpc\ChannelCredentials::createComposite(
518 $creds1, $callCreds1);
519 $creds3 = Grpc\ChannelCredentials::createComposite(
520 $creds1, $callCreds2);
522 // Similar to the test above, anytime a ChannelCredentials
523 // object is composed with a CallCredentials object, the
524 // underlying grpc channel will always be separate and not
526 $this->channel1 = new Grpc\Channel('localhost:50027',
527 ["credentials" => $creds1,
528 "grpc_target_persist_bound" => 3,
530 $this->channel2 = new Grpc\Channel('localhost:50027',
531 ["credentials" => $creds2]);
532 $this->channel3 = new Grpc\Channel('localhost:50027',
533 ["credentials" => $creds3]);
535 // try to connect on channel1
536 $state = $this->channel1->getConnectivityState(true);
537 $this->waitUntilNotIdle($this->channel1);
539 $state = $this->channel1->getConnectivityState();
540 $this->assertConnecting($state);
541 $state = $this->channel2->getConnectivityState();
542 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
543 $state = $this->channel3->getConnectivityState();
544 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
546 $this->channel1->close();
547 $this->channel2->close();
548 $this->channel3->close();
551 public function testPersistentChannelForceNew()
553 $this->channel1 = new Grpc\Channel('localhost:50028', [
554 "grpc_target_persist_bound" => 2,
556 // even though all the channel params are the same, channel2
557 // has a new and different underlying channel
558 $this->channel2 = new Grpc\Channel('localhost:50028',
559 ["force_new" => true]);
561 // try to connect on channel1
562 $state = $this->channel1->getConnectivityState(true);
563 $this->waitUntilNotIdle($this->channel1);
565 $state = $this->channel1->getConnectivityState();
566 $this->assertConnecting($state);
567 $state = $this->channel2->getConnectivityState();
568 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
570 $this->channel1->close();
571 $this->channel2->close();
574 public function testPersistentChannelForceNewOldChannelIdle1()
577 $this->channel1 = new Grpc\Channel('localhost:50029', [
578 "grpc_target_persist_bound" => 2,
580 $this->channel2 = new Grpc\Channel('localhost:50029',
581 ["force_new" => true]);
582 // channel3 shares with channel1
583 $this->channel3 = new Grpc\Channel('localhost:50029', []);
585 // try to connect on channel2
586 $state = $this->channel2->getConnectivityState(true);
587 $this->waitUntilNotIdle($this->channel2);
588 $state = $this->channel1->getConnectivityState();
589 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
590 $state = $this->channel2->getConnectivityState();
591 $this->assertConnecting($state);
592 $state = $this->channel3->getConnectivityState();
593 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
595 $this->channel1->close();
596 $this->channel2->close();
599 public function testPersistentChannelForceNewOldChannelIdle2()
602 $this->channel1 = new Grpc\Channel('localhost:50032', [
603 "grpc_target_persist_bound" => 2,
605 $this->channel2 = new Grpc\Channel('localhost:50032', []);
607 // try to connect on channel2
608 $state = $this->channel1->getConnectivityState(true);
609 $this->waitUntilNotIdle($this->channel2);
610 $state = $this->channel1->getConnectivityState();
611 $this->assertConnecting($state);
612 $state = $this->channel2->getConnectivityState();
613 $this->assertConnecting($state);
615 $this->channel1->close();
616 $this->channel2->close();
619 public function testPersistentChannelForceNewOldChannelClose1()
622 $this->channel1 = new Grpc\Channel('localhost:50130', [
623 "grpc_target_persist_bound" => 2,
625 $this->channel2 = new Grpc\Channel('localhost:50130',
626 ["force_new" => true]);
627 // channel3 shares with channel1
628 $this->channel3 = new Grpc\Channel('localhost:50130', []);
630 $this->channel1->close();
632 $state = $this->channel2->getConnectivityState();
633 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
635 // channel3 is still usable. We need to exclude the possibility that in
636 // testPersistentChannelForceNewOldChannelClose2, the exception is thrown
637 // by channel1 and channel2.
638 $state = $this->channel3->getConnectivityState();
639 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
643 * @expectedException RuntimeException
645 public function testPersistentChannelForceNewOldChannelClose2()
648 $this->channel1 = new Grpc\Channel('localhost:50230', [
649 "grpc_target_persist_bound" => 2,
651 $this->channel2 = new Grpc\Channel('localhost:50230',
652 ["force_new" => true]);
653 // channel3 shares with channel1
654 $this->channel3 = new Grpc\Channel('localhost:50230', []);
656 $this->channel1->close();
658 $state = $this->channel2->getConnectivityState();
659 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
661 // channel3 is still usable
662 $state = $this->channel3->getConnectivityState();
663 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
665 // channel 1 is closed
666 $this->channel1->getConnectivityState();
669 public function testPersistentChannelForceNewNewChannelClose()
672 $this->channel1 = new Grpc\Channel('localhost:50031', [
673 "grpc_target_persist_bound" => 2,
675 $this->channel2 = new Grpc\Channel('localhost:50031',
676 ["force_new" => true]);
677 $this->channel3 = new Grpc\Channel('localhost:50031', []);
679 $this->channel2->close();
681 $state = $this->channel1->getConnectivityState();
682 $this->assertEquals(GRPC\CHANNEL_IDLE, $state);
684 // can still connect on channel1
685 $state = $this->channel1->getConnectivityState(true);
686 $this->waitUntilNotIdle($this->channel1);
688 $state = $this->channel1->getConnectivityState();
689 $this->assertConnecting($state);
691 $this->channel1->close();