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 */ 19require_once realpath(dirname(__FILE__).'/../../vendor/autoload.php'); 20 21// The following includes are needed when using protobuf 3.1.0 22// and will suppress warnings when using protobuf 3.2.0+ 23@include_once dirname(__FILE__).'/math.pb.php'; 24@include_once dirname(__FILE__).'/math_grpc_pb.php'; 25 26abstract class AbstractGeneratedCodeTest extends \PHPUnit\Framework\TestCase 27{ 28 /** 29 * These tests require that a server exporting the math service must be 30 * running on $GRPC_TEST_HOST. 31 */ 32 protected static $client; 33 34 protected static $clientOptions = array( 35 'grpc.service_config' => '{ 36 "loadBalancingPolicy": "round_robin", 37 "methodConfig": [ 38 { 39 "name": [ 40 { 41 "service": "math.Math" 42 } 43 ], 44 "waitForReady": true, 45 "retryPolicy": { 46 "maxAttempts": 2, 47 "initialBackoff": "0.2s", 48 "maxBackoff": "4s", 49 "backoffMultiplier": 2, 50 "retryableStatusCodes": [ 51 "UNAVAILABLE", 52 "RESOURCE_EXHAUSTED", 53 "DEADLINE_EXCEEDED" 54 ] 55 } 56 } 57 ] 58 }', 59 'grpc.enable_retries' => 1, 60 ); 61 62 public function testWaitForNotReady() 63 { 64 $this->assertFalse(self::$client->waitForReady(1)); 65 } 66 67 public function testWaitForReady() 68 { 69 $this->assertTrue(self::$client->waitForReady(250000)); 70 } 71 72 public function testAlreadyReady() 73 { 74 $this->assertTrue(self::$client->waitForReady(250000)); 75 $this->assertTrue(self::$client->waitForReady(100)); 76 } 77 78 public function testGetTarget() 79 { 80 $this->assertTrue(is_string(self::$client->getTarget())); 81 } 82 83 public function testClose() 84 { 85 $this->expectException(\InvalidArgumentException::class); 86 self::$client->close(); 87 $div_arg = new Math\DivArgs(); 88 $call = self::$client->Div($div_arg); 89 } 90 91 public function testInvalidMetadata() 92 { 93 $this->expectException(\InvalidArgumentException::class); 94 $div_arg = new Math\DivArgs(); 95 $call = self::$client->Div($div_arg, [' ' => 'abc123']); 96 } 97 98 public function testMetadata() 99 { 100 $div_arg = new Math\DivArgs(); 101 $div_arg->setDividend(7); 102 $div_arg->setDivisor(4); 103 $call = self::$client->Div($div_arg, ['somekey' => ['abc123']]); 104 // $this->assertNotNull($call); 105 list($response, $status) = $call->wait(); 106 $this->assertSame(\Grpc\STATUS_OK, $status->code); 107 } 108 109 public function testMetadataKey() 110 { 111 $div_arg = new Math\DivArgs(); 112 $div_arg->setDividend(7); 113 $div_arg->setDivisor(4); 114 $call = self::$client->Div($div_arg, ['somekey_-1' => ['abc123']]); 115 list($response, $status) = $call->wait(); 116 $this->assertSame(\Grpc\STATUS_OK, $status->code); 117 } 118 119 public function testMetadataKeyWithDot() 120 { 121 $div_arg = new Math\DivArgs(); 122 $div_arg->setDividend(7); 123 $div_arg->setDivisor(4); 124 $call = self::$client->Div($div_arg, ['someKEY._-1' => ['abc123']]); 125 list($response, $status) = $call->wait(); 126 $this->assertSame(\Grpc\STATUS_OK, $status->code); 127 } 128 129 public function testMetadataInvalidKey() 130 { 131 $this->expectException(\InvalidArgumentException::class); 132 $div_arg = new Math\DivArgs(); 133 $call = self::$client->Div($div_arg, ['(somekey)' => ['abc123']]); 134 } 135 136 public function testGetCallMetadata() 137 { 138 $div_arg = new Math\DivArgs(); 139 $call = self::$client->Div($div_arg); 140 $this->assertTrue(is_array($call->getMetadata())); 141 } 142 143 public function testTimeout() 144 { 145 $div_arg = new Math\DivArgs(); 146 $div_arg->setDividend(7); 147 $div_arg->setDivisor(4); 148 $call = self::$client->Div($div_arg, [], ['timeout' => 1]); 149 list($response, $status) = $call->wait(); 150 $this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code); 151 } 152 153 public function testCancel() 154 { 155 $div_arg = new Math\DivArgs(); 156 $call = self::$client->Div($div_arg); 157 $call->cancel(); 158 list($response, $status) = $call->wait(); 159 $this->assertSame(\Grpc\STATUS_CANCELLED, $status->code); 160 } 161 162 public function testRetry() 163 { 164 $metadata = [ 165 'response-unavailable' => [ 166 'server response STATUS_UNAVAILABLE so client will retry' 167 ], 168 ]; 169 $div_arg = new Math\DivArgs(); 170 $div_arg->setDividend(7); 171 $div_arg->setDivisor(4); 172 $call = self::$client->Div($div_arg, $metadata); 173 list($response, $status) = $call->wait(); 174 $this->assertSame(\Grpc\STATUS_UNAVAILABLE, $status->code); 175 $this->assertSame('1', $status->metadata['unavailable-retry-attempts'][0]); 176 } 177 178 public function testCallCredentialsCallback() 179 { 180 $div_arg = new Math\DivArgs(); 181 $div_arg->setDividend(7); 182 $div_arg->setDivisor(4); 183 $call = self::$client->Div($div_arg, array(), array( 184 'call_credentials_callback' => function ($context) { 185 return array(); 186 }, 187 )); 188 list($response, $status) = $call->wait(); 189 $this->assertSame(\Grpc\STATUS_OK, $status->code); 190 } 191 192 public function testInsecureChannelCallCredentialsCallback() 193 { 194 $div_arg = new Math\DivArgs(); 195 $div_arg->setDividend(7); 196 $div_arg->setDivisor(4); 197 $client = new Math\MathClient( 198 getenv('GRPC_TEST_INSECURE_HOST'), [ 199 'credentials' => Grpc\ChannelCredentials::createInsecure(), 200 ]); 201 $call = $client->Div($div_arg, array(), array( 202 'call_credentials_callback' => function ($context) { 203 return array(); 204 }, 205 )); 206 list($response, $status) = $call->wait(); 207 $this->assertSame(\Grpc\STATUS_OK, $status->code); 208 } 209 210 public function testInvalidMethodName() 211 { 212 $this->expectException(\InvalidArgumentException::class); 213 $invalid_client = new PhonyInvalidClient('host', [ 214 'credentials' => Grpc\ChannelCredentials::createInsecure(), 215 ]); 216 $div_arg = new Math\DivArgs(); 217 $invalid_client->InvalidUnaryCall($div_arg); 218 } 219 220 public function testMissingCredentials() 221 { 222 $this->expectException(\Exception::class); 223 $this->expectExceptionMessage("The opts['credentials'] key is now required."); 224 $invalid_client = new PhonyInvalidClient('host', [ 225 ]); 226 } 227 228 public function testPrimaryUserAgentString() 229 { 230 $invalid_client = new PhonyInvalidClient('host', [ 231 'credentials' => Grpc\ChannelCredentials::createInsecure(), 232 'grpc.primary_user_agent' => 'testUserAgent', 233 ]); 234 $this->assertTrue(TRUE); // to avoid no assert warning 235 } 236 237 public function testWriteFlags() 238 { 239 $div_arg = new Math\DivArgs(); 240 $div_arg->setDividend(7); 241 $div_arg->setDivisor(4); 242 $call = self::$client->Div($div_arg, [], 243 ['flags' => Grpc\WRITE_NO_COMPRESS]); 244 $this->assertTrue(is_string($call->getPeer())); 245 list($response, $status) = $call->wait(); 246 $this->assertSame(1, $response->getQuotient()); 247 $this->assertSame(3, $response->getRemainder()); 248 $this->assertSame(\Grpc\STATUS_OK, $status->code); 249 } 250 251 public function testWriteFlagsServerStreaming() 252 { 253 $fib_arg = new Math\FibArgs(); 254 $fib_arg->setLimit(7); 255 $call = self::$client->Fib($fib_arg, [], 256 ['flags' => Grpc\WRITE_NO_COMPRESS]); 257 $result_array = iterator_to_array($call->responses()); 258 $status = $call->getStatus(); 259 $this->assertSame(\Grpc\STATUS_OK, $status->code); 260 } 261 262 public function testWriteFlagsClientStreaming() 263 { 264 $call = self::$client->Sum(); 265 $num = new Math\Num(); 266 $num->setNum(1); 267 $call->write($num, ['flags' => Grpc\WRITE_NO_COMPRESS]); 268 list($response, $status) = $call->wait(); 269 $this->assertSame(\Grpc\STATUS_OK, $status->code); 270 } 271 272 public function testWriteFlagsBidiStreaming() 273 { 274 $call = self::$client->DivMany(); 275 $div_arg = new Math\DivArgs(); 276 $div_arg->setDividend(7); 277 $div_arg->setDivisor(4); 278 $call->write($div_arg, ['flags' => Grpc\WRITE_NO_COMPRESS]); 279 $response = $call->read(); 280 $call->writesDone(); 281 $status = $call->getStatus(); 282 $this->assertSame(\Grpc\STATUS_OK, $status->code); 283 } 284 285 public function testSimpleRequest() 286 { 287 $div_arg = new Math\DivArgs(); 288 $div_arg->setDividend(7); 289 $div_arg->setDivisor(4); 290 $call = self::$client->Div($div_arg); 291 $this->assertTrue(is_string($call->getPeer())); 292 list($response, $status) = $call->wait(); 293 $this->assertSame(1, $response->getQuotient()); 294 $this->assertSame(3, $response->getRemainder()); 295 $this->assertSame(\Grpc\STATUS_OK, $status->code); 296 } 297 298 public function testServerStreaming() 299 { 300 $fib_arg = new Math\FibArgs(); 301 $fib_arg->setLimit(7); 302 $call = self::$client->Fib($fib_arg); 303 $this->assertTrue(is_string($call->getPeer())); 304 $result_array = iterator_to_array($call->responses()); 305 $extract_num = function ($num) { 306 return $num->getNum(); 307 }; 308 $values = array_map($extract_num, $result_array); 309 $this->assertSame([1, 1, 2, 3, 5, 8, 13], $values); 310 $status = $call->getStatus(); 311 $this->assertSame(\Grpc\STATUS_OK, $status->code); 312 } 313 314 public function testClientStreaming() 315 { 316 $call = self::$client->Sum(); 317 $this->assertTrue(is_string($call->getPeer())); 318 for ($i = 0; $i < 7; ++$i) { 319 $num = new Math\Num(); 320 $num->setNum($i); 321 $call->write($num); 322 } 323 list($response, $status) = $call->wait(); 324 $this->assertSame(21, $response->getNum()); 325 $this->assertSame(\Grpc\STATUS_OK, $status->code); 326 } 327 328 public function testBidiStreaming() 329 { 330 $call = self::$client->DivMany(); 331 $this->assertTrue(is_string($call->getPeer())); 332 for ($i = 0; $i < 7; ++$i) { 333 $div_arg = new Math\DivArgs(); 334 $div_arg->setDividend(2 * $i + 1); 335 $div_arg->setDivisor(2); 336 $call->write($div_arg); 337 $response = $call->read(); 338 $this->assertSame($i, $response->getQuotient()); 339 $this->assertSame(1, $response->getRemainder()); 340 } 341 $call->writesDone(); 342 $status = $call->getStatus(); 343 $this->assertSame(\Grpc\STATUS_OK, $status->code); 344 } 345 346 public function testReuseCall() 347 { 348 $this->expectException(\LogicException::class); 349 $this->expectExceptionMessage("start_batch was called incorrectly"); 350 $div_arg = new Math\DivArgs(); 351 $div_arg->setDividend(7); 352 $div_arg->setDivisor(4); 353 $call = self::$client->Div($div_arg, [], ['timeout' => 1000000]); 354 355 list($response, $status) = $call->wait(); 356 $this->assertSame(\Grpc\STATUS_OK, $status->code); 357 list($response, $status) = $call->wait(); 358 } 359} 360 361class PhonyInvalidClient extends \Grpc\BaseStub 362{ 363 public function InvalidUnaryCall(\Math\DivArgs $argument, 364 $metadata = [], 365 $options = []) 366 { 367 return $this->_simpleRequest('invalidMethodName', 368 $argument, 369 function () {}, 370 $metadata, 371 $options); 372 } 373} 374