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