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 */ 19class EndToEndTest extends \PHPUnit\Framework\TestCase 20{ 21 private $server; 22 private $port; 23 private $channel; 24 25 public function setUp(): void 26 { 27 $this->server = new Grpc\Server([]); 28 $this->port = $this->server->addHttp2Port('0.0.0.0:0'); 29 $this->channel = new Grpc\Channel('localhost:'.$this->port, [ 30 "force_new" => true, 31 ]); 32 $this->server->start(); 33 } 34 35 public function tearDown(): void 36 { 37 $this->channel->close(); 38 unset($this->server); 39 } 40 41 public function testSimpleRequestBody() 42 { 43 $deadline = Grpc\Timeval::infFuture(); 44 $status_text = 'xyz'; 45 $call = new Grpc\Call($this->channel, 46 'phony_method', 47 $deadline); 48 49 $event = $call->startBatch([ 50 Grpc\OP_SEND_INITIAL_METADATA => [], 51 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 52 ]); 53 54 $this->assertTrue($event->send_metadata); 55 $this->assertTrue($event->send_close); 56 57 $event = $this->server->requestCall(); 58 $this->assertSame('phony_method', $event->method); 59 $server_call = $event->call; 60 61 $event = $server_call->startBatch([ 62 Grpc\OP_SEND_INITIAL_METADATA => [], 63 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 64 'metadata' => [], 65 'code' => Grpc\STATUS_OK, 66 'details' => $status_text, 67 ], 68 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 69 ]); 70 71 $this->assertTrue($event->send_metadata); 72 $this->assertTrue($event->send_status); 73 $this->assertFalse($event->cancelled); 74 75 $event = $call->startBatch([ 76 Grpc\OP_RECV_INITIAL_METADATA => true, 77 Grpc\OP_RECV_STATUS_ON_CLIENT => true, 78 ]); 79 80 $status = $event->status; 81 $this->assertSame([], $status->metadata); 82 $this->assertSame(Grpc\STATUS_OK, $status->code); 83 $this->assertSame($status_text, $status->details); 84 85 unset($call); 86 unset($server_call); 87 } 88 89 public function testMessageWriteFlags() 90 { 91 $deadline = Grpc\Timeval::infFuture(); 92 $req_text = 'message_write_flags_test'; 93 $status_text = 'xyz'; 94 $call = new Grpc\Call($this->channel, 95 'phony_method', 96 $deadline); 97 98 $event = $call->startBatch([ 99 Grpc\OP_SEND_INITIAL_METADATA => [], 100 Grpc\OP_SEND_MESSAGE => ['message' => $req_text, 101 'flags' => Grpc\WRITE_NO_COMPRESS, ], 102 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 103 ]); 104 105 $this->assertTrue($event->send_metadata); 106 $this->assertTrue($event->send_close); 107 108 $event = $this->server->requestCall(); 109 $this->assertSame('phony_method', $event->method); 110 $server_call = $event->call; 111 112 $event = $server_call->startBatch([ 113 Grpc\OP_SEND_INITIAL_METADATA => [], 114 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 115 'metadata' => [], 116 'code' => Grpc\STATUS_OK, 117 'details' => $status_text, 118 ], 119 ]); 120 121 $event = $call->startBatch([ 122 Grpc\OP_RECV_INITIAL_METADATA => true, 123 Grpc\OP_RECV_STATUS_ON_CLIENT => true, 124 ]); 125 126 $status = $event->status; 127 $this->assertSame([], $status->metadata); 128 $this->assertSame(Grpc\STATUS_OK, $status->code); 129 $this->assertSame($status_text, $status->details); 130 131 unset($call); 132 unset($server_call); 133 } 134 135 public function testClientServerFullRequestResponse() 136 { 137 $deadline = Grpc\Timeval::infFuture(); 138 $req_text = 'client_server_full_request_response'; 139 $reply_text = 'reply:client_server_full_request_response'; 140 $status_text = 'status:client_server_full_response_text'; 141 142 $call = new Grpc\Call($this->channel, 143 'phony_method', 144 $deadline); 145 146 $event = $call->startBatch([ 147 Grpc\OP_SEND_INITIAL_METADATA => [], 148 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 149 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 150 ]); 151 152 $this->assertTrue($event->send_metadata); 153 $this->assertTrue($event->send_close); 154 $this->assertTrue($event->send_message); 155 156 $event = $this->server->requestCall(); 157 $this->assertSame('phony_method', $event->method); 158 $server_call = $event->call; 159 160 $event = $server_call->startBatch([ 161 Grpc\OP_RECV_MESSAGE => true, 162 ]); 163 $this->assertSame($req_text, $event->message); 164 165 $event = $server_call->startBatch([ 166 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 167 Grpc\OP_SEND_INITIAL_METADATA => [], 168 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 169 'metadata' => [], 170 'code' => Grpc\STATUS_OK, 171 'details' => $status_text, 172 ], 173 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 174 ]); 175 176 $this->assertTrue($event->send_metadata); 177 $this->assertTrue($event->send_status); 178 $this->assertTrue($event->send_message); 179 $this->assertFalse($event->cancelled); 180 181 $event = $call->startBatch([ 182 Grpc\OP_RECV_INITIAL_METADATA => true, 183 Grpc\OP_RECV_MESSAGE => true, 184 Grpc\OP_RECV_STATUS_ON_CLIENT => true, 185 ]); 186 187 $this->assertSame([], $event->metadata); 188 $this->assertSame($reply_text, $event->message); 189 $status = $event->status; 190 $this->assertSame([], $status->metadata); 191 $this->assertSame(Grpc\STATUS_OK, $status->code); 192 $this->assertSame($status_text, $status->details); 193 194 unset($call); 195 unset($server_call); 196 } 197 198 public function testInvalidClientMessageArray() 199 { 200 $this->expectException(\InvalidArgumentException::class); 201 $deadline = Grpc\Timeval::infFuture(); 202 $req_text = 'client_server_full_request_response'; 203 $reply_text = 'reply:client_server_full_request_response'; 204 $status_text = 'status:client_server_full_response_text'; 205 206 $call = new Grpc\Call($this->channel, 207 'phony_method', 208 $deadline); 209 210 $event = $call->startBatch([ 211 Grpc\OP_SEND_INITIAL_METADATA => [], 212 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 213 Grpc\OP_SEND_MESSAGE => 'invalid', 214 ]); 215 } 216 217 public function testInvalidClientMessageString() 218 { 219 $this->expectException(\InvalidArgumentException::class); 220 $deadline = Grpc\Timeval::infFuture(); 221 $req_text = 'client_server_full_request_response'; 222 $reply_text = 'reply:client_server_full_request_response'; 223 $status_text = 'status:client_server_full_response_text'; 224 225 $call = new Grpc\Call($this->channel, 226 'phony_method', 227 $deadline); 228 229 $event = $call->startBatch([ 230 Grpc\OP_SEND_INITIAL_METADATA => [], 231 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 232 Grpc\OP_SEND_MESSAGE => ['message' => 0], 233 ]); 234 } 235 236 public function testInvalidClientMessageFlags() 237 { 238 $this->expectException(\InvalidArgumentException::class); 239 $deadline = Grpc\Timeval::infFuture(); 240 $req_text = 'client_server_full_request_response'; 241 $reply_text = 'reply:client_server_full_request_response'; 242 $status_text = 'status:client_server_full_response_text'; 243 244 $call = new Grpc\Call($this->channel, 245 'phony_method', 246 $deadline); 247 248 $event = $call->startBatch([ 249 Grpc\OP_SEND_INITIAL_METADATA => [], 250 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 251 Grpc\OP_SEND_MESSAGE => ['message' => 'abc', 252 'flags' => 'invalid', 253 ], 254 ]); 255 } 256 257 public function testInvalidServerStatusMetadata() 258 { 259 $this->expectException(\InvalidArgumentException::class); 260 $deadline = Grpc\Timeval::infFuture(); 261 $req_text = 'client_server_full_request_response'; 262 $reply_text = 'reply:client_server_full_request_response'; 263 $status_text = 'status:client_server_full_response_text'; 264 265 $call = new Grpc\Call($this->channel, 266 'phony_method', 267 $deadline); 268 269 $event = $call->startBatch([ 270 Grpc\OP_SEND_INITIAL_METADATA => [], 271 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 272 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 273 ]); 274 275 $this->assertTrue($event->send_metadata); 276 $this->assertTrue($event->send_close); 277 $this->assertTrue($event->send_message); 278 279 $event = $this->server->requestCall(); 280 $this->assertSame('phony_method', $event->method); 281 $server_call = $event->call; 282 283 $event = $server_call->startBatch([ 284 Grpc\OP_SEND_INITIAL_METADATA => [], 285 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 286 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 287 'metadata' => 'invalid', 288 'code' => Grpc\STATUS_OK, 289 'details' => $status_text, 290 ], 291 Grpc\OP_RECV_MESSAGE => true, 292 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 293 ]); 294 } 295 296 public function testInvalidServerStatusCode() 297 { 298 $this->expectException(\InvalidArgumentException::class); 299 $deadline = Grpc\Timeval::infFuture(); 300 $req_text = 'client_server_full_request_response'; 301 $reply_text = 'reply:client_server_full_request_response'; 302 $status_text = 'status:client_server_full_response_text'; 303 304 $call = new Grpc\Call($this->channel, 305 'phony_method', 306 $deadline); 307 308 $event = $call->startBatch([ 309 Grpc\OP_SEND_INITIAL_METADATA => [], 310 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 311 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 312 ]); 313 314 $this->assertTrue($event->send_metadata); 315 $this->assertTrue($event->send_close); 316 $this->assertTrue($event->send_message); 317 318 $event = $this->server->requestCall(); 319 $this->assertSame('phony_method', $event->method); 320 $server_call = $event->call; 321 322 $event = $server_call->startBatch([ 323 Grpc\OP_SEND_INITIAL_METADATA => [], 324 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 325 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 326 'metadata' => [], 327 'code' => 'invalid', 328 'details' => $status_text, 329 ], 330 Grpc\OP_RECV_MESSAGE => true, 331 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 332 ]); 333 } 334 335 public function testMissingServerStatusCode() 336 { 337 $this->expectException(\InvalidArgumentException::class); 338 $deadline = Grpc\Timeval::infFuture(); 339 $req_text = 'client_server_full_request_response'; 340 $reply_text = 'reply:client_server_full_request_response'; 341 $status_text = 'status:client_server_full_response_text'; 342 343 $call = new Grpc\Call($this->channel, 344 'phony_method', 345 $deadline); 346 347 $event = $call->startBatch([ 348 Grpc\OP_SEND_INITIAL_METADATA => [], 349 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 350 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 351 ]); 352 353 $this->assertTrue($event->send_metadata); 354 $this->assertTrue($event->send_close); 355 $this->assertTrue($event->send_message); 356 357 $event = $this->server->requestCall(); 358 $this->assertSame('phony_method', $event->method); 359 $server_call = $event->call; 360 361 $event = $server_call->startBatch([ 362 Grpc\OP_SEND_INITIAL_METADATA => [], 363 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 364 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 365 'metadata' => [], 366 'details' => $status_text, 367 ], 368 Grpc\OP_RECV_MESSAGE => true, 369 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 370 ]); 371 } 372 373 public function testInvalidServerStatusDetails() 374 { 375 $this->expectException(\InvalidArgumentException::class); 376 $deadline = Grpc\Timeval::infFuture(); 377 $req_text = 'client_server_full_request_response'; 378 $reply_text = 'reply:client_server_full_request_response'; 379 $status_text = 'status:client_server_full_response_text'; 380 381 $call = new Grpc\Call($this->channel, 382 'phony_method', 383 $deadline); 384 385 $event = $call->startBatch([ 386 Grpc\OP_SEND_INITIAL_METADATA => [], 387 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 388 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 389 ]); 390 391 $this->assertTrue($event->send_metadata); 392 $this->assertTrue($event->send_close); 393 $this->assertTrue($event->send_message); 394 395 $event = $this->server->requestCall(); 396 $this->assertSame('phony_method', $event->method); 397 $server_call = $event->call; 398 399 $event = $server_call->startBatch([ 400 Grpc\OP_SEND_INITIAL_METADATA => [], 401 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 402 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 403 'metadata' => [], 404 'code' => Grpc\STATUS_OK, 405 'details' => 0, 406 ], 407 Grpc\OP_RECV_MESSAGE => true, 408 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 409 ]); 410 } 411 412 public function testMissingServerStatusDetails() 413 { 414 $this->expectException(\InvalidArgumentException::class); 415 $deadline = Grpc\Timeval::infFuture(); 416 $req_text = 'client_server_full_request_response'; 417 $reply_text = 'reply:client_server_full_request_response'; 418 $status_text = 'status:client_server_full_response_text'; 419 420 $call = new Grpc\Call($this->channel, 421 'phony_method', 422 $deadline); 423 424 $event = $call->startBatch([ 425 Grpc\OP_SEND_INITIAL_METADATA => [], 426 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 427 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 428 ]); 429 430 $this->assertTrue($event->send_metadata); 431 $this->assertTrue($event->send_close); 432 $this->assertTrue($event->send_message); 433 434 $event = $this->server->requestCall(); 435 $this->assertSame('phony_method', $event->method); 436 $server_call = $event->call; 437 438 $event = $server_call->startBatch([ 439 Grpc\OP_SEND_INITIAL_METADATA => [], 440 Grpc\OP_SEND_MESSAGE => ['message' => $reply_text], 441 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 442 'metadata' => [], 443 'code' => Grpc\STATUS_OK, 444 ], 445 Grpc\OP_RECV_MESSAGE => true, 446 Grpc\OP_RECV_CLOSE_ON_SERVER => true, 447 ]); 448 } 449 450 public function testInvalidStartBatchKey() 451 { 452 $this->expectException(\InvalidArgumentException::class); 453 $deadline = Grpc\Timeval::infFuture(); 454 $req_text = 'client_server_full_request_response'; 455 $reply_text = 'reply:client_server_full_request_response'; 456 $status_text = 'status:client_server_full_response_text'; 457 458 $call = new Grpc\Call($this->channel, 459 'phony_method', 460 $deadline); 461 462 $event = $call->startBatch([ 463 9999999 => [], 464 ]); 465 } 466 467 public function testInvalidStartBatch() 468 { 469 $this->expectException(\LogicException::class); 470 $deadline = Grpc\Timeval::infFuture(); 471 $req_text = 'client_server_full_request_response'; 472 $reply_text = 'reply:client_server_full_request_response'; 473 $status_text = 'status:client_server_full_response_text'; 474 475 $call = new Grpc\Call($this->channel, 476 'phony_method', 477 $deadline); 478 479 $event = $call->startBatch([ 480 Grpc\OP_SEND_INITIAL_METADATA => [], 481 Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, 482 Grpc\OP_SEND_MESSAGE => ['message' => $req_text], 483 Grpc\OP_SEND_STATUS_FROM_SERVER => [ 484 'metadata' => [], 485 'code' => Grpc\STATUS_OK, 486 'details' => 'abc', 487 ], 488 ]); 489 } 490 491 public function testGetTarget() 492 { 493 $this->assertTrue(is_string($this->channel->getTarget())); 494 } 495 496 public function testGetConnectivityState() 497 { 498 $this->assertTrue($this->channel->getConnectivityState() == 499 Grpc\CHANNEL_IDLE); 500 } 501 502 public function testWatchConnectivityStateFailed() 503 { 504 $idle_state = $this->channel->getConnectivityState(); 505 $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); 506 507 $now = Grpc\Timeval::now(); 508 $delta = new Grpc\Timeval(50000); // should timeout 509 $deadline = $now->add($delta); 510 511 $this->assertFalse($this->channel->watchConnectivityState( 512 $idle_state, $deadline)); 513 } 514 515 public function testWatchConnectivityStateSuccess() 516 { 517 $idle_state = $this->channel->getConnectivityState(true); 518 $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); 519 520 $now = Grpc\Timeval::now(); 521 $delta = new Grpc\Timeval(3000000); // should finish well before 522 $deadline = $now->add($delta); 523 524 $this->assertTrue($this->channel->watchConnectivityState( 525 $idle_state, $deadline)); 526 527 $new_state = $this->channel->getConnectivityState(); 528 $this->assertTrue($idle_state != $new_state); 529 } 530 531 public function testWatchConnectivityStateDoNothing() 532 { 533 $idle_state = $this->channel->getConnectivityState(); 534 $this->assertTrue($idle_state == Grpc\CHANNEL_IDLE); 535 536 $now = Grpc\Timeval::now(); 537 $delta = new Grpc\Timeval(50000); 538 $deadline = $now->add($delta); 539 540 $this->assertFalse($this->channel->watchConnectivityState( 541 $idle_state, $deadline)); 542 543 $new_state = $this->channel->getConnectivityState(); 544 $this->assertTrue($new_state == Grpc\CHANNEL_IDLE); 545 } 546 547 public function testGetConnectivityStateInvalidParam() 548 { 549 $this->expectException(\InvalidArgumentException::class); 550 $this->assertTrue($this->channel->getConnectivityState( 551 new Grpc\Timeval())); 552 } 553 554 public function testWatchConnectivityStateInvalidParam() 555 { 556 $this->expectException(\InvalidArgumentException::class); 557 $this->assertTrue($this->channel->watchConnectivityState( 558 0, 1000)); 559 } 560 561 public function testChannelConstructorInvalidParam() 562 { 563 $this->expectException(\InvalidArgumentException::class); 564 $this->channel = new Grpc\Channel('localhost:'.$this->port, null); 565 } 566 567 public function testClose() 568 { 569 $this->assertNull($this->channel->close()); 570 } 571} 572