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(): void 26 { 27 } 28 29 public function tearDown(): void 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 public function testPersistentChannelSharedChannelClose() 171 { 172 $this->expectException(\RuntimeException::class); 173 $this->expectExceptionMessage("startBatch Error. Channel is closed"); 174 // same underlying channel 175 $this->channel1 = new Grpc\Channel('localhost:10001', [ 176 "grpc_target_persist_bound" => 2, 177 ]); 178 $this->channel2 = new Grpc\Channel('localhost:10001', []); 179 $this->server = new Grpc\Server([]); 180 $this->port = $this->server->addHttp2Port('localhost:10001'); 181 $this->server->start(); 182 183 // channel2 can still be use 184 $state = $this->channel2->getConnectivityState(); 185 $this->assertEquals(GRPC\CHANNEL_IDLE, $state); 186 187 $call1 = new Grpc\Call($this->channel1, 188 '/foo', 189 Grpc\Timeval::infFuture()); 190 $call2 = new Grpc\Call($this->channel2, 191 '/foo', 192 Grpc\Timeval::infFuture()); 193 $call3 = new Grpc\Call($this->channel1, 194 '/foo', 195 Grpc\Timeval::infFuture()); 196 $call4 = new Grpc\Call($this->channel2, 197 '/foo', 198 Grpc\Timeval::infFuture()); 199 $batch = [ 200 Grpc\OP_SEND_INITIAL_METADATA => [], 201 ]; 202 203 $result = $call1->startBatch($batch); 204 $this->assertTrue($result->send_metadata); 205 $result = $call2->startBatch($batch); 206 $this->assertTrue($result->send_metadata); 207 208 $this->channel1->close(); 209 // After closing channel1, channel2 can still be use 210 $result = $call4->startBatch($batch); 211 $this->assertTrue($result->send_metadata); 212 // channel 1 is closed, it will throw an exception. 213 $result = $call3->startBatch($batch); 214 } 215 216 public function testPersistentChannelTargetDefaultUpperBound() 217 { 218 $this->channel1 = new Grpc\Channel('localhost:10002', []); 219 $channel1_info = $this->channel1->getChannelInfo(); 220 $this->assertEquals($channel1_info['target_upper_bound'], 1); 221 $this->assertEquals($channel1_info['target_current_size'], 1); 222 } 223 224 public function testPersistentChannelTargetUpperBoundZero() 225 { 226 $this->channel1 = new Grpc\Channel('localhost:10002', [ 227 "grpc_target_persist_bound" => 0, 228 ]); 229 // channel1 will not be persisted. 230 $channel1_info = $this->channel1->getChannelInfo(); 231 $this->assertEquals($channel1_info['target_upper_bound'], 0); 232 $this->assertEquals($channel1_info['target_current_size'], 0); 233 $plist_info = $this->channel1->getPersistentList(); 234 $this->assertEquals(0, count($plist_info)); 235 } 236 237 public function testPersistentChannelTargetUpperBoundNotZero() 238 { 239 $this->channel1 = new Grpc\Channel('localhost:10003', [ 240 "grpc_target_persist_bound" => 3, 241 ]); 242 $channel1_info = $this->channel1->getChannelInfo(); 243 $this->assertEquals($channel1_info['target_upper_bound'], 3); 244 $this->assertEquals($channel1_info['target_current_size'], 1); 245 246 // The upper bound should not be changed 247 $this->channel2 = new Grpc\Channel('localhost:10003', []); 248 $channel2_info = $this->channel2->getChannelInfo(); 249 $this->assertEquals($channel2_info['target_upper_bound'], 3); 250 $this->assertEquals($channel2_info['target_current_size'], 1); 251 252 // The upper bound should not be changed 253 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 254 null); 255 $this->channel3 = new Grpc\Channel('localhost:10003', 256 ['credentials' => $channel_credentials]); 257 $channel3_info = $this->channel3->getChannelInfo(); 258 $this->assertEquals($channel3_info['target_upper_bound'], 3); 259 $this->assertEquals($channel3_info['target_current_size'], 2); 260 261 // The upper bound should not be changed 262 $this->channel4 = new Grpc\Channel('localhost:10003', [ 263 "grpc_target_persist_bound" => 5, 264 ]); 265 $channel4_info = $this->channel4->getChannelInfo(); 266 $this->assertEquals($channel4_info['target_upper_bound'], 5); 267 $this->assertEquals($channel4_info['target_current_size'], 2); 268 } 269 270 public function testPersistentChannelDefaultOutBound1() 271 { 272 $this->channel1 = new Grpc\Channel('localhost:10004', []); 273 // Make channel1 not IDLE. 274 $this->channel1->getConnectivityState(true); 275 $this->waitUntilNotIdle($this->channel1); 276 $channel1_info = $this->channel1->getChannelInfo(); 277 $this->assertConnecting($channel1_info['connectivity_status']); 278 279 // Since channel1 is CONNECTING, channel 2 will not be persisted 280 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 281 null); 282 $this->channel2 = new Grpc\Channel('localhost:10004', 283 ['credentials' => $channel_credentials]); 284 $channel2_info = $this->channel2->getChannelInfo(); 285 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 286 287 // By default, target 'localhost:10011' only persist one channel. 288 // Since channel1 is not Idle channel2 will not be persisted. 289 $plist_info = $this->channel1->getPersistentList(); 290 $this->assertEquals(1, count($plist_info)); 291 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 292 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 293 } 294 295 public function testPersistentChannelDefaultOutBound2() 296 { 297 $this->channel1 = new Grpc\Channel('localhost:10005', []); 298 $channel1_info = $this->channel1->getChannelInfo(); 299 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 300 301 // Although channel1 is IDLE, channel1 still has reference to the underline 302 // gRPC channel. channel2 will not be persisted 303 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 304 null); 305 $this->channel2 = new Grpc\Channel('localhost:10005', 306 ['credentials' => $channel_credentials]); 307 $channel2_info = $this->channel2->getChannelInfo(); 308 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 309 310 // By default, target 'localhost:10011' only persist one channel. 311 // Since channel1 Idle, channel2 will be persisted. 312 $plist_info = $this->channel1->getPersistentList(); 313 $this->assertEquals(1, count($plist_info)); 314 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 315 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 316 } 317 318 public function testPersistentChannelDefaultOutBound3() 319 { 320 $this->channel1 = new Grpc\Channel('localhost:10006', []); 321 $channel1_info = $this->channel1->getChannelInfo(); 322 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 323 324 $this->channel1->close(); 325 // channel1 is closed, no reference holds to the underline channel. 326 // channel2 can be persisted. 327 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 328 null); 329 $this->channel2 = new Grpc\Channel('localhost:10006', 330 ['credentials' => $channel_credentials]); 331 $channel2_info = $this->channel2->getChannelInfo(); 332 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 333 334 // By default, target 'localhost:10011' only persist one channel. 335 // Since channel1 Idle, channel2 will be persisted. 336 $plist_info = $this->channel2->getPersistentList(); 337 $this->assertEquals(1, count($plist_info)); 338 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 339 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 340 } 341 342 public function testPersistentChannelTwoUpperBound() 343 { 344 $this->channel1 = new Grpc\Channel('localhost:10007', [ 345 "grpc_target_persist_bound" => 2, 346 ]); 347 $channel1_info = $this->channel1->getChannelInfo(); 348 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel1_info['connectivity_status']); 349 350 // Since channel1 is IDLE, channel 1 will be deleted 351 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 352 null); 353 $this->channel2 = new Grpc\Channel('localhost:10007', 354 ['credentials' => $channel_credentials]); 355 $channel2_info = $this->channel2->getChannelInfo(); 356 $this->assertEquals(GRPC\CHANNEL_IDLE, $channel2_info['connectivity_status']); 357 358 $plist_info = $this->channel1->getPersistentList(); 359 $this->assertEquals(2, count($plist_info)); 360 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 361 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 362 } 363 364 public function testPersistentChannelTwoUpperBoundOutBound1() 365 { 366 $this->channel1 = new Grpc\Channel('localhost:10011', [ 367 "grpc_target_persist_bound" => 2, 368 ]); 369 $channel1_info = $this->channel1->getChannelInfo(); 370 371 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 372 null); 373 $this->channel2 = new Grpc\Channel('localhost:10011', 374 ['credentials' => $channel_credentials]); 375 $channel2_info = $this->channel2->getChannelInfo(); 376 377 // Close channel1, so that new channel can be persisted. 378 $this->channel1->close(); 379 380 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 381 null); 382 $this->channel3 = new Grpc\Channel('localhost:10011', 383 ['credentials' => $channel_credentials]); 384 $channel3_info = $this->channel3->getChannelInfo(); 385 386 $plist_info = $this->channel1->getPersistentList(); 387 $this->assertEquals(2, count($plist_info)); 388 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 389 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 390 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 391 } 392 393 public function testPersistentChannelTwoUpperBoundOutBound2() 394 { 395 $this->channel1 = new Grpc\Channel('localhost:10012', [ 396 "grpc_target_persist_bound" => 2, 397 ]); 398 $channel1_info = $this->channel1->getChannelInfo(); 399 400 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 401 null); 402 $this->channel2 = new Grpc\Channel('localhost:10012', 403 ['credentials' => $channel_credentials]); 404 $channel2_info = $this->channel2->getChannelInfo(); 405 406 // Close channel2, so that new channel can be persisted. 407 $this->channel2->close(); 408 409 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 410 null); 411 $this->channel3 = new Grpc\Channel('localhost:10012', 412 ['credentials' => $channel_credentials]); 413 $channel3_info = $this->channel3->getChannelInfo(); 414 415 $plist_info = $this->channel1->getPersistentList(); 416 $this->assertEquals(2, count($plist_info)); 417 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 418 $this->assertArrayNotHasKey($channel2_info['key'], $plist_info); 419 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 420 } 421 422 public function testPersistentChannelTwoUpperBoundOutBound3() 423 { 424 $this->channel1 = new Grpc\Channel('localhost:10013', [ 425 "grpc_target_persist_bound" => 2, 426 ]); 427 $channel1_info = $this->channel1->getChannelInfo(); 428 429 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 430 null); 431 $this->channel2 = new Grpc\Channel('localhost:10013', 432 ['credentials' => $channel_credentials]); 433 $this->channel2->getConnectivityState(true); 434 $this->waitUntilNotIdle($this->channel2); 435 $channel2_info = $this->channel2->getChannelInfo(); 436 $this->assertConnecting($channel2_info['connectivity_status']); 437 438 // Only one channel will be deleted 439 $this->channel1->close(); 440 $this->channel2->close(); 441 442 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 443 null); 444 $this->channel3 = new Grpc\Channel('localhost:10013', 445 ['credentials' => $channel_credentials]); 446 $channel3_info = $this->channel3->getChannelInfo(); 447 448 // Only the Idle Channel will be deleted 449 $plist_info = $this->channel1->getPersistentList(); 450 $this->assertEquals(2, count($plist_info)); 451 $this->assertArrayNotHasKey($channel1_info['key'], $plist_info); 452 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 453 $this->assertArrayHasKey($channel3_info['key'], $plist_info); 454 } 455 456 public function testPersistentChannelTwoUpperBoundOutBound4() 457 { 458 $this->channel1 = new Grpc\Channel('localhost:10014', [ 459 "grpc_target_persist_bound" => 2, 460 ]); 461 $this->channel1->getConnectivityState(true); 462 $this->waitUntilNotIdle($this->channel1); 463 $channel1_info = $this->channel1->getChannelInfo(); 464 $this->assertConnecting($channel1_info['connectivity_status']); 465 466 $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, 467 null); 468 $this->channel2 = new Grpc\Channel('localhost:10014', 469 ['credentials' => $channel_credentials]); 470 $this->channel2->getConnectivityState(true); 471 $this->waitUntilNotIdle($this->channel2); 472 $channel2_info = $this->channel2->getChannelInfo(); 473 $this->assertConnecting($channel2_info['connectivity_status']); 474 475 $channel_credentials = Grpc\ChannelCredentials::createSsl("a", null, 476 null); 477 $this->channel3 = new Grpc\Channel('localhost:10014', 478 ['credentials' => $channel_credentials]); 479 $channel3_info = $this->channel3->getChannelInfo(); 480 481 // Channel3 will not be persisted 482 $plist_info = $this->channel1->getPersistentList(); 483 $this->assertEquals(2, count($plist_info)); 484 $this->assertArrayHasKey($channel1_info['key'], $plist_info); 485 $this->assertArrayHasKey($channel2_info['key'], $plist_info); 486 $this->assertArrayNotHasKey($channel3_info['key'], $plist_info); 487 } 488} 489