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