1<?php 2/* 3 * 4 * Copyright 2015 gRPC authors. 5 * 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 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 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. 17 * 18 */ 19 20/** 21 * @group persistent_list_bound_tests 22 */ 23class PersistentListTest extends PHPUnit_Framework_TestCase 24{ 25 public function setUp() 26 { 27 } 28 29 public function tearDown() 30 { 31 $channel_clean_persistent = 32 new Grpc\Channel('localhost:50010', []); 33 $plist = $channel_clean_persistent->getPersistentList(); 34 $channel_clean_persistent->cleanPersistentList(); 35 } 36 37 public function waitUntilNotIdle($channel) { 38 for ($i = 0; $i < 10; $i++) { 39 $now = Grpc\Timeval::now(); 40 $deadline = $now->add(new Grpc\Timeval(1000)); 41 if ($channel->watchConnectivityState(GRPC\CHANNEL_IDLE, 42 $deadline)) { 43 return true; 44 } 45 } 46 $this->assertTrue(false); 47 } 48 49 public function assertConnecting($state) { 50 $this->assertTrue($state == GRPC\CHANNEL_CONNECTING || 51 $state == GRPC\CHANNEL_TRANSIENT_FAILURE); 52 } 53 54 public function testInitHelper() 55 { 56 // PersistentList is not empty at the beginning of the tests 57 // because phpunit will cache the channels created by other test 58 // files. 59 } 60 61 62 public function testChannelNotPersist() 63 { 64 $this->channel1 = new Grpc\Channel('localhost:1', ['force_new' => true]); 65 $channel1_info = $this->channel1->getChannelInfo(); 66 $plist_info = $this->channel1->getPersistentList(); 67 $this->assertEquals($channel1_info['target'], 'localhost:1'); 68 $this->assertEquals($channel1_info['ref_count'], 1); 69 $this->assertEquals($channel1_info['connectivity_status'], 70 GRPC\CHANNEL_IDLE); 71 $this->assertEquals(count($plist_info), 0); 72 $this->channel1->close(); 73 } 74 75 public function testPersistentChannelCreateOneChannel() 76 { 77 $this->channel1 = new Grpc\Channel('localhost:1', []); 78 $channel1_info = $this->channel1->getChannelInfo(); 79 $plist_info = $this->channel1->getPersistentList(); 80 $this->assertEquals($channel1_info['target'], 'localhost:1'); 81 $this->assertEquals($channel1_info['ref_count'], 2); 82 $this->assertEquals($channel1_info['connectivity_status'], 83 GRPC\CHANNEL_IDLE); 84 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 85 $this->assertEquals(count($plist_info), 1); 86 $this->channel1->close(); 87 } 88 89 public function testPersistentChannelCreateMultipleChannels() 90 { 91 $this->channel1 = new Grpc\Channel('localhost:1', []); 92 $plist_info = $this->channel1->getPersistentList(); 93 $this->assertEquals(count($plist_info), 1); 94 95 $this->channel2 = new Grpc\Channel('localhost:2', []); 96 $plist_info = $this->channel1->getPersistentList(); 97 $this->assertEquals(count($plist_info), 2); 98 99 $this->channel3 = new Grpc\Channel('localhost:3', []); 100 $plist_info = $this->channel1->getPersistentList(); 101 $this->assertEquals(count($plist_info), 3); 102 } 103 104 public function testPersistentChannelStatusChange() 105 { 106 $this->channel1 = new Grpc\Channel('localhost:4', []); 107 $channel1_info = $this->channel1->getChannelInfo(); 108 $this->assertEquals($channel1_info['connectivity_status'], 109 GRPC\CHANNEL_IDLE); 110 111 $this->channel1->getConnectivityState(true); 112 $this->waitUntilNotIdle($this->channel1); 113 $channel1_info = $this->channel1->getChannelInfo(); 114 $this->assertConnecting($channel1_info['connectivity_status']); 115 $this->channel1->close(); 116 } 117 118 public function testPersistentChannelCloseChannel() 119 { 120 $this->channel1 = new Grpc\Channel('localhost:1', []); 121 $this->channel2 = new Grpc\Channel('localhost:1', []); 122 123 $channel1_info = $this->channel1->getChannelInfo(); 124 $this->assertEquals($channel1_info['ref_count'], 3); 125 $plist_info = $this->channel1->getPersistentList(); 126 $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 3); 127 128 $this->channel1->close(); 129 $plist_info = $this->channel1->getPersistentList(); 130 $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2); 131 132 $this->channel2->close(); 133 $plist_info = $this->channel1->getPersistentList(); 134 $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 1); 135 } 136 137 public function testPersistentChannelSameTarget() 138 { 139 $this->channel1 = new Grpc\Channel('localhost:1', []); 140 $this->channel2 = new Grpc\Channel('localhost:1', []); 141 $plist = $this->channel2->getPersistentList(); 142 $channel1_info = $this->channel1->getChannelInfo(); 143 $channel2_info = $this->channel2->getChannelInfo(); 144 // $channel1 and $channel2 shares the same channel, thus only 1 145 // channel should be in the persistent list. 146 $this->assertEquals($channel1_info['key'], $channel2_info['key']); 147 $this->assertArrayHasKey($channel1_info['key'], $plist); 148 $this->assertEquals(count($plist), 1); 149 $this->channel1->close(); 150 $this->channel2->close(); 151 } 152 153 public function testPersistentChannelDifferentTarget() 154 { 155 $this->channel1 = new Grpc\Channel('localhost:1', []); 156 $channel1_info = $this->channel1->getChannelInfo(); 157 $this->channel2 = new Grpc\Channel('localhost:2', []); 158 $channel2_info = $this->channel1->getChannelInfo(); 159 $plist_info = $this->channel1->getPersistentList(); 160 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 161 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 162 $this->assertEquals($plist_info[$channel1_info['key']]['ref_count'], 2); 163 $this->assertEquals($plist_info[$channel2_info['key']]['ref_count'], 2); 164 $plist_info = $this->channel1->getPersistentList(); 165 $this->assertEquals(count($plist_info), 2); 166 $this->channel1->close(); 167 $this->channel2->close(); 168 } 169 170 /** 171 * @expectedException RuntimeException 172 * @expectedExceptionMessage startBatch Error. Channel is closed 173 */ 174 public function testPersistentChannelSharedChannelClose() 175 { 176 // same underlying channel 177 $this->channel1 = new Grpc\Channel('localhost:10001', [ 178 "grpc_target_persist_bound" => 2, 179 ]); 180 $this->channel2 = new Grpc\Channel('localhost:10001', []); 181 $this->server = new Grpc\Server([]); 182 $this->port = $this->server->addHttp2Port('localhost:10001'); 183 184 // channel2 can still be use 185 $state = $this->channel2->getConnectivityState(); 186 $this->assertEquals(GRPC\CHANNEL_IDLE, $state); 187 188 $call1 = new Grpc\Call($this->channel1, 189 '/foo', 190 Grpc\Timeval::infFuture()); 191 $call2 = new Grpc\Call($this->channel2, 192 '/foo', 193 Grpc\Timeval::infFuture()); 194 $call3 = new Grpc\Call($this->channel1, 195 '/foo', 196 Grpc\Timeval::infFuture()); 197 $call4 = new Grpc\Call($this->channel2, 198 '/foo', 199 Grpc\Timeval::infFuture()); 200 $batch = [ 201 Grpc\OP_SEND_INITIAL_METADATA => [], 202 ]; 203 204 $result = $call1->startBatch($batch); 205 $this->assertTrue($result->send_metadata); 206 $result = $call2->startBatch($batch); 207 $this->assertTrue($result->send_metadata); 208 209 $this->channel1->close(); 210 // After closing channel1, channel2 can still be use 211 $result = $call4->startBatch($batch); 212 $this->assertTrue($result->send_metadata); 213 // channel 1 is closed, it will throw an exception. 214 $result = $call3->startBatch($batch); 215 } 216 217 public function testPersistentChannelTargetDefaultUpperBound() 218 { 219 $this->channel1 = new Grpc\Channel('localhost:10002', []); 220 $channel1_info = $this->channel1->getChannelInfo(); 221 $this->assertEquals($channel1_info['target_upper_bound'], 1); 222 $this->assertEquals($channel1_info['target_current_size'], 1); 223 } 224 225 public function testPersistentChannelTargetUpperBoundZero() 226 { 227 $this->channel1 = new Grpc\Channel('localhost:10002', [ 228 "grpc_target_persist_bound" => 0, 229 ]); 230 // channel1 will not be persisted. 231 $channel1_info = $this->channel1->getChannelInfo(); 232 $this->assertEquals($channel1_info['target_upper_bound'], 0); 233 $this->assertEquals($channel1_info['target_current_size'], 0); 234 $plist_info = $this->channel1->getPersistentList(); 235 $this->assertEquals(0, count($plist_info)); 236 } 237 238 public function testPersistentChannelTargetUpperBoundNotZero() 239 { 240 $this->channel1 = new Grpc\Channel('localhost:10003', [ 241 "grpc_target_persist_bound" => 3, 242 ]); 243 $channel1_info = $this->channel1->getChannelInfo(); 244 $this->assertEquals($channel1_info['target_upper_bound'], 3); 245 $this->assertEquals($channel1_info['target_current_size'], 1); 246 247 // The upper bound should not be changed 248 $this->channel2 = new Grpc\Channel('localhost:10003', []); 249 $channel2_info = $this->channel2->getChannelInfo(); 250 $this->assertEquals($channel2_info['target_upper_bound'], 3); 251 $this->assertEquals($channel2_info['target_current_size'], 1); 252 253 // The upper bound should not be changed 254 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 255 null); 256 $this->channel3 = new Grpc\Channel('localhost:10003', 257 ['credentials' => $channel_credentials]); 258 $channel3_info = $this->channel3->getChannelInfo(); 259 $this->assertEquals($channel3_info['target_upper_bound'], 3); 260 $this->assertEquals($channel3_info['target_current_size'], 2); 261 262 // The upper bound should not be changed 263 $this->channel4 = new Grpc\Channel('localhost:10003', [ 264 "grpc_target_persist_bound" => 5, 265 ]); 266 $channel4_info = $this->channel4->getChannelInfo(); 267 $this->assertEquals($channel4_info['target_upper_bound'], 5); 268 $this->assertEquals($channel4_info['target_current_size'], 2); 269 } 270 271 public function testPersistentChannelDefaultOutBound1() 272 { 273 $this->channel1 = new Grpc\Channel('localhost:10004', []); 274 // Make channel1 not IDLE. 275 $this->channel1->getConnectivityState(true); 276 $this->waitUntilNotIdle($this->channel1); 277 $channel1_info = $this->channel1->getChannelInfo(); 278 $this->assertConnecting($channel1_info['connectivity_status']); 279 280 // Since channel1 is CONNECTING, channel 2 will not be persisted 281 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 282 null); 283 $this->channel2 = new Grpc\Channel('localhost:10004', 284 ['credentials' => $channel_credentials]); 285 $channel2_info = $this->channel2->getChannelInfo(); 286 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 287 288 // By default, target 'localhost:10011' only persist one channel. 289 // Since channel1 is not Idle channel2 will not be persisted. 290 $plist_info = $this->channel1->getPersistentList(); 291 $this->assertEquals(1, count($plist_info)); 292 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 293 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 294 } 295 296 public function testPersistentChannelDefaultOutBound2() 297 { 298 $this->channel1 = new Grpc\Channel('localhost:10005', []); 299 $channel1_info = $this->channel1->getChannelInfo(); 300 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 301 302 // Although channel1 is IDLE, channel1 still has reference to the underline 303 // gRPC channel. channel2 will not be persisted 304 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 305 null); 306 $this->channel2 = new Grpc\Channel('localhost:10005', 307 ['credentials' => $channel_credentials]); 308 $channel2_info = $this->channel2->getChannelInfo(); 309 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 310 311 // By default, target 'localhost:10011' only persist one channel. 312 // Since channel1 Idle, channel2 will be persisted. 313 $plist_info = $this->channel1->getPersistentList(); 314 $this->assertEquals(1, count($plist_info)); 315 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 316 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 317 } 318 319 public function testPersistentChannelDefaultOutBound3() 320 { 321 $this->channel1 = new Grpc\Channel('localhost:10006', []); 322 $channel1_info = $this->channel1->getChannelInfo(); 323 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 324 325 $this->channel1->close(); 326 // channel1 is closed, no reference holds to the underline channel. 327 // channel2 can be persisted. 328 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 329 null); 330 $this->channel2 = new Grpc\Channel('localhost:10006', 331 ['credentials' => $channel_credentials]); 332 $channel2_info = $this->channel2->getChannelInfo(); 333 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 334 335 // By default, target 'localhost:10011' only persist one channel. 336 // Since channel1 Idle, channel2 will be persisted. 337 $plist_info = $this->channel2->getPersistentList(); 338 $this->assertEquals(1, count($plist_info)); 339 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 340 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 341 } 342 343 public function testPersistentChannelTwoUpperBound() 344 { 345 $this->channel1 = new Grpc\Channel('localhost:10007', [ 346 "grpc_target_persist_bound" => 2, 347 ]); 348 $channel1_info = $this->channel1->getChannelInfo(); 349 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 350 351 // Since channel1 is IDLE, channel 1 will be deleted 352 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 353 null); 354 $this->channel2 = new Grpc\Channel('localhost:10007', 355 ['credentials' => $channel_credentials]); 356 $channel2_info = $this->channel2->getChannelInfo(); 357 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 358 359 $plist_info = $this->channel1->getPersistentList(); 360 $this->assertEquals(2, count($plist_info)); 361 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 362 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 363 } 364 365 public function testPersistentChannelTwoUpperBoundOutBound1() 366 { 367 $this->channel1 = new Grpc\Channel('localhost:10011', [ 368 "grpc_target_persist_bound" => 2, 369 ]); 370 $channel1_info = $this->channel1->getChannelInfo(); 371 372 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 373 null); 374 $this->channel2 = new Grpc\Channel('localhost:10011', 375 ['credentials' => $channel_credentials]); 376 $channel2_info = $this->channel2->getChannelInfo(); 377 378 // Close channel1, so that new channel can be persisted. 379 $this->channel1->close(); 380 381 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 382 null); 383 $this->channel3 = new Grpc\Channel('localhost:10011', 384 ['credentials' => $channel_credentials]); 385 $channel3_info = $this->channel3->getChannelInfo(); 386 387 $plist_info = $this->channel1->getPersistentList(); 388 $this->assertEquals(2, count($plist_info)); 389 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 390 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 391 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 392 } 393 394 public function testPersistentChannelTwoUpperBoundOutBound2() 395 { 396 $this->channel1 = new Grpc\Channel('localhost:10012', [ 397 "grpc_target_persist_bound" => 2, 398 ]); 399 $channel1_info = $this->channel1->getChannelInfo(); 400 401 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 402 null); 403 $this->channel2 = new Grpc\Channel('localhost:10012', 404 ['credentials' => $channel_credentials]); 405 $channel2_info = $this->channel2->getChannelInfo(); 406 407 // Close channel2, so that new channel can be persisted. 408 $this->channel2->close(); 409 410 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 411 null); 412 $this->channel3 = new Grpc\Channel('localhost:10012', 413 ['credentials' => $channel_credentials]); 414 $channel3_info = $this->channel3->getChannelInfo(); 415 416 $plist_info = $this->channel1->getPersistentList(); 417 $this->assertEquals(2, count($plist_info)); 418 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 419 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 420 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 421 } 422 423 public function testPersistentChannelTwoUpperBoundOutBound3() 424 { 425 $this->channel1 = new Grpc\Channel('localhost:10013', [ 426 "grpc_target_persist_bound" => 2, 427 ]); 428 $channel1_info = $this->channel1->getChannelInfo(); 429 430 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 431 null); 432 $this->channel2 = new Grpc\Channel('localhost:10013', 433 ['credentials' => $channel_credentials]); 434 $this->channel2->getConnectivityState(true); 435 $this->waitUntilNotIdle($this->channel2); 436 $channel2_info = $this->channel2->getChannelInfo(); 437 $this->assertConnecting($channel2_info['connectivity_status']); 438 439 // Only one channel will be deleted 440 $this->channel1->close(); 441 $this->channel2->close(); 442 443 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 444 null); 445 $this->channel3 = new Grpc\Channel('localhost:10013', 446 ['credentials' => $channel_credentials]); 447 $channel3_info = $this->channel3->getChannelInfo(); 448 449 // Only the Idle Channel will be deleted 450 $plist_info = $this->channel1->getPersistentList(); 451 $this->assertEquals(2, count($plist_info)); 452 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 453 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 454 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 455 } 456 457 public function testPersistentChannelTwoUpperBoundOutBound4() 458 { 459 $this->channel1 = new Grpc\Channel('localhost:10014', [ 460 "grpc_target_persist_bound" => 2, 461 ]); 462 $this->channel1->getConnectivityState(true); 463 $this->waitUntilNotIdle($this->channel1); 464 $channel1_info = $this->channel1->getChannelInfo(); 465 $this->assertConnecting($channel1_info['connectivity_status']); 466 467 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 468 null); 469 $this->channel2 = new Grpc\Channel('localhost:10014', 470 ['credentials' => $channel_credentials]); 471 $this->channel2->getConnectivityState(true); 472 $this->waitUntilNotIdle($this->channel2); 473 $channel2_info = $this->channel2->getChannelInfo(); 474 $this->assertConnecting($channel2_info['connectivity_status']); 475 476 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 477 null); 478 $this->channel3 = new Grpc\Channel('localhost:10014', 479 ['credentials' => $channel_credentials]); 480 $channel3_info = $this->channel3->getChannelInfo(); 481 482 // Channel3 will not be persisted 483 $plist_info = $this->channel1->getPersistentList(); 484 $this->assertEquals(2, count($plist_info)); 485 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 486 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 487 $this->assertArrayNotHasKey($channel3_info['key'], $plist_info); 488 } 489} 490