From b667e632c386dd7ca25c99e4a47f9969faaa0086 Mon Sep 17 00:00:00 2001 From: Hector Mendoza Jacobo Date: Wed, 24 Apr 2024 20:26:15 +0000 Subject: [PATCH] Add unit testing for GRPC only clients --- composer.json | 3 +- rules_php_gapic/php_gapic.bzl | 2 +- src/Utils/Transport.php | 2 +- .../BasicGrpcOnly/basicGrpcOnly.proto | 53 +++++ .../basic_grpc_only_service.yaml | 10 + .../samples/BasicGrpcOnlyClient/a_method.php | 57 +++++ .../BasicGrpcOnlyClient/method_with_args.php | 73 ++++++ .../out/src/Client/BasicGrpcOnlyClient.php | 216 ++++++++++++++++++ .../BasicGrpcOnly/out/src/gapic_metadata.json | 28 +++ .../basic_grpc_only_client_config.json | 36 +++ .../basic_grpc_only_descriptor_config.php | 36 +++ .../basic_grpc_only_rest_client_config.php | 39 ++++ .../Unit/Client/BasicGrpcOnlyClientTest.php | 207 +++++++++++++++++ tests/Unit/ProtoTests/ClientTest.php | 9 + tests/Unit/ProtoTests/GoldenUpdateMain.php | 6 + 15 files changed, 774 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/basicGrpcOnly.proto create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/basic_grpc_only_service.yaml create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/a_method.php create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/method_with_args.php create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/src/Client/BasicGrpcOnlyClient.php create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/src/gapic_metadata.json create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_client_config.json create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_descriptor_config.php create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_rest_client_config.php create mode 100644 tests/Unit/ProtoTests/BasicGrpcOnly/out/tests/Unit/Client/BasicGrpcOnlyClientTest.php diff --git a/composer.json b/composer.json index 9b8563c1..b92419c3 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "Testing\\DisableSnippets\\": "tests/Unit/ProtoTests/DisableSnippets/out/src", "Testing\\GrpcServiceConfig\\": "tests/Unit/ProtoTests/GrpcServiceConfig/out/src", "Testing\\ResourceNames\\": "tests/Unit/ProtoTests/ResourceNames/out/src", - "Testing\\RoutingHeaders\\": "tests/Unit/ProtoTests/RoutingHeaders/out/src" + "Testing\\RoutingHeaders\\": "tests/Unit/ProtoTests/RoutingHeaders/out/src", + "Testing\\BasicGrpcOnly\\": "tests/Unit/ProtoTests/BasicGrpcOnly/out/src" } }, "require": { diff --git a/rules_php_gapic/php_gapic.bzl b/rules_php_gapic/php_gapic.bzl index 3c9f379b..3cc82ff2 100644 --- a/rules_php_gapic/php_gapic.bzl +++ b/rules_php_gapic/php_gapic.bzl @@ -70,7 +70,7 @@ def php_gapic_srcjar( if transport == None: transport = "grpc+rest" if transport != "grpc+rest" and transport != "rest" and transport != "grpc": - fail("Error: Only 'grpc+rest' or 'rest' transports are supported") + fail("Error: Only 'grpc+rest', 'rest' or `grpc` transports are supported") # Set plugin arguments. plugin_args = ["metadata"] # Generate the gapic_metadata.json file. diff --git a/src/Utils/Transport.php b/src/Utils/Transport.php index ec6c964d..15efdcee 100644 --- a/src/Utils/Transport.php +++ b/src/Utils/Transport.php @@ -39,7 +39,7 @@ public static function parseTransport(?string $transport): int return static::REST; } if ($transport === "grpc") { - throw new \Exception("gRPC-only PHP clients are not supported at this time"); + return static::GRPC; } throw new \Exception("Transport $transport not supported"); diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/basicGrpcOnly.proto b/tests/Unit/ProtoTests/BasicGrpcOnly/basicGrpcOnly.proto new file mode 100644 index 00000000..648f06ae --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/basicGrpcOnly.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package testing.basicGrpcOnly; + +// php_namespace option not included; to test generating namespace from proto package. + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; + +// This is a basicGrpcOnly service. +service BasicGrpcOnly { + option (google.api.default_host) = "basicGrpcOnly.example.com"; + option (google.api.oauth_scopes) = "scope1,scope2"; + + // Test summary text for AMethod + rpc AMethod(Request) returns(Response) { + option (google.api.http) = { + post: "/path:aMethod" + body: "*" + }; + } + + // Test including method args. + rpc MethodWithArgs(RequestWithArgs) returns(Response) { + option (google.api.http) = { + post: "/path:methodWithArgs" + body: "*" + }; + }; +} + +message Request { +} + +message PartOfRequestA {} +message PartOfRequestB {} +message PartOfRequestC {} + +message RequestWithArgs { + // A required field... + string a_string = 1 [(google.api.field_behavior) = REQUIRED]; + // ...and an optional field. + int32 an_int = 2; + // ...and a repeated message type, which checks that an extra import is *not* added, + // in contrast to a paginated method where an extra import *is* added. + repeated PartOfRequestA part_of_request_a = 4 [(google.api.field_behavior) = REQUIRED]; + repeated PartOfRequestB part_of_request_b = 5; + PartOfRequestC part_of_request_c = 6; +} + +message Response { +} diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/basic_grpc_only_service.yaml b/tests/Unit/ProtoTests/BasicGrpcOnly/basic_grpc_only_service.yaml new file mode 100644 index 00000000..fa826b1c --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/basic_grpc_only_service.yaml @@ -0,0 +1,10 @@ +type: google.api.Service +config_version: 3 + +authentication: + rules: + - selector: 'testing.basicGrpcOnly.BasicGrpcOnly.*' + oauth: + canonical_scopes: |- + scope1, + scope2 diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/a_method.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/a_method.php new file mode 100644 index 00000000..1a946daa --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/a_method.php @@ -0,0 +1,57 @@ +aMethod($request); + printf('Response data: %s' . PHP_EOL, $response->serializeToJsonString()); + } catch (ApiException $ex) { + printf('Call failed with message: %s' . PHP_EOL, $ex->getMessage()); + } +} +// [END basicGrpcOnly_generated_BasicGrpcOnly_AMethod_sync] diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/method_with_args.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/method_with_args.php new file mode 100644 index 00000000..79f84411 --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/samples/BasicGrpcOnlyClient/method_with_args.php @@ -0,0 +1,73 @@ +setAString($aString) + ->setPartOfRequestA($partOfRequestA); + + // Call the API and handle any network failures. + try { + /** @var Response $response */ + $response = $basicGrpcOnlyClient->methodWithArgs($request); + printf('Response data: %s' . PHP_EOL, $response->serializeToJsonString()); + } catch (ApiException $ex) { + printf('Call failed with message: %s' . PHP_EOL, $ex->getMessage()); + } +} + +/** + * Helper to execute the sample. + * + * This sample has been automatically generated and should be regarded as a code + * template only. It will require modifications to work: + * - It may require correct/in-range values for request initialization. + * - It may require specifying regional endpoints when creating the service client, + * please see the apiEndpoint client configuration option for more details. + */ +function callSample(): void +{ + $aString = '[A_STRING]'; + + method_with_args_sample($aString); +} +// [END basicGrpcOnly_generated_BasicGrpcOnly_MethodWithArgs_sync] diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/Client/BasicGrpcOnlyClient.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/Client/BasicGrpcOnlyClient.php new file mode 100644 index 00000000..b0c5e31a --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/Client/BasicGrpcOnlyClient.php @@ -0,0 +1,216 @@ + self::SERVICE_NAME, + 'apiEndpoint' => self::SERVICE_ADDRESS . ':' . self::DEFAULT_SERVICE_PORT, + 'clientConfig' => __DIR__ . '/../resources/basic_grpc_only_client_config.json', + 'descriptorsConfigPath' => __DIR__ . '/../resources/basic_grpc_only_descriptor_config.php', + 'credentialsConfig' => [ + 'defaultScopes' => self::$serviceScopes, + ], + 'transportConfig' => [ + 'rest' => [ + 'restClientConfigPath' => __DIR__ . '/../resources/basic_grpc_only_rest_client_config.php', + ], + ], + ]; + } + + /** Implements ClientOptionsTrait::supportedTransports. */ + private static function supportedTransports() + { + return [ + 'grpc', + 'grpc-fallback', + ]; + } + + /** + * Constructor. + * + * @param array $options { + * Optional. Options for configuring the service API wrapper. + * + * @type string $apiEndpoint + * The address of the API remote host. May optionally include the port, formatted + * as ":". Default 'basicGrpcOnly.example.com:443'. + * @type string|array|FetchAuthTokenInterface|CredentialsWrapper $credentials + * The credentials to be used by the client to authorize API calls. This option + * accepts either a path to a credentials file, or a decoded credentials file as a + * PHP array. + * *Advanced usage*: In addition, this option can also accept a pre-constructed + * {@see \Google\Auth\FetchAuthTokenInterface} object or + * {@see \Google\ApiCore\CredentialsWrapper} object. Note that when one of these + * objects are provided, any settings in $credentialsConfig will be ignored. + * @type array $credentialsConfig + * Options used to configure credentials, including auth token caching, for the + * client. For a full list of supporting configuration options, see + * {@see \Google\ApiCore\CredentialsWrapper::build()} . + * @type bool $disableRetries + * Determines whether or not retries defined by the client configuration should be + * disabled. Defaults to `false`. + * @type string|array $clientConfig + * Client method configuration, including retry settings. This option can be either + * a path to a JSON file, or a PHP array containing the decoded JSON data. By + * default this settings points to the default client config file, which is + * provided in the resources folder. + * @type string|TransportInterface $transport + * The transport used for executing network requests. At the moment, supports only + * `rest`. *Advanced usage*: Additionally, it is possible to pass in an already + * instantiated {@see \Google\ApiCore\Transport\TransportInterface} object. Note + * that when this object is provided, any settings in $transportConfig, and any + * $apiEndpoint setting, will be ignored. + * @type array $transportConfig + * Configuration options that will be used to construct the transport. Options for + * each supported transport type should be passed in a key for that transport. For + * example: + * $transportConfig = [ + * 'rest' => [...], + * ]; + * See the {@see \Google\ApiCore\Transport\RestTransport::build()} method for the + * supported options. + * @type callable $clientCertSource + * A callable which returns the client cert as a string. This can be used to + * provide a certificate and private key to the transport layer for mTLS. + * } + * + * @throws ValidationException + */ + public function __construct(array $options = []) + { + $clientOptions = $this->buildClientOptions($options); + $this->setClientOptions($clientOptions); + } + + /** Handles execution of the async variants for each documented method. */ + public function __call($method, $args) + { + if (substr($method, -5) !== 'Async') { + trigger_error('Call to undefined method ' . __CLASS__ . "::$method()", E_USER_ERROR); + } + + array_unshift($args, substr($method, 0, -5)); + return call_user_func_array([$this, 'startAsyncCall'], $args); + } + + /** + * Test summary text for AMethod + * + * The async variant is {@see BasicGrpcOnlyClient::aMethodAsync()} . + * + * @example samples/BasicGrpcOnlyClient/a_method.php + * + * @param Request $request A request to house fields associated with the call. + * @param array $callOptions { + * Optional. + * + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a {@see RetrySettings} object, or an + * associative array of retry settings parameters. See the documentation on + * {@see RetrySettings} for example usage. + * } + * + * @return Response + * + * @throws ApiException Thrown if the API call fails. + */ + public function aMethod(Request $request, array $callOptions = []): Response + { + return $this->startApiCall('AMethod', $request, $callOptions)->wait(); + } + + /** + * Test including method args. + * + * The async variant is {@see BasicGrpcOnlyClient::methodWithArgsAsync()} . + * + * @example samples/BasicGrpcOnlyClient/method_with_args.php + * + * @param RequestWithArgs $request A request to house fields associated with the call. + * @param array $callOptions { + * Optional. + * + * @type RetrySettings|array $retrySettings + * Retry settings to use for this call. Can be a {@see RetrySettings} object, or an + * associative array of retry settings parameters. See the documentation on + * {@see RetrySettings} for example usage. + * } + * + * @return Response + * + * @throws ApiException Thrown if the API call fails. + */ + public function methodWithArgs(RequestWithArgs $request, array $callOptions = []): Response + { + return $this->startApiCall('MethodWithArgs', $request, $callOptions)->wait(); + } +} diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/gapic_metadata.json b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/gapic_metadata.json new file mode 100644 index 00000000..64d4b583 --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/gapic_metadata.json @@ -0,0 +1,28 @@ +{ + "schema": "1.0", + "comment": "This file maps proto services\/RPCs to the corresponding library clients\/methods", + "language": "php", + "protoPackage": "testing.basicGrpcOnly", + "libraryPackage": "Testing\\BasicGrpcOnly", + "services": { + "BasicGrpcOnly": { + "clients": { + "grpc": { + "libraryClient": "BasicGrpcOnlyGapicClient", + "rpcs": { + "AMethod": { + "methods": [ + "aMethod" + ] + }, + "MethodWithArgs": { + "methods": [ + "methodWithArgs" + ] + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_client_config.json b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_client_config.json new file mode 100644 index 00000000..798ffdce --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_client_config.json @@ -0,0 +1,36 @@ +{ + "interfaces": { + "testing.basicGrpcOnly.BasicGrpcOnly": { + "retry_codes": { + "idempotent": [ + "DEADLINE_EXCEEDED", + "UNAVAILABLE" + ], + "non_idempotent": [] + }, + "retry_params": { + "default": { + "initial_retry_delay_millis": 100, + "retry_delay_multiplier": 1.3, + "max_retry_delay_millis": 60000, + "initial_rpc_timeout_millis": 20000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 20000, + "total_timeout_millis": 600000 + } + }, + "methods": { + "AMethod": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default" + }, + "MethodWithArgs": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default" + } + } + } + } +} diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_descriptor_config.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_descriptor_config.php new file mode 100644 index 00000000..ed7ae8da --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_descriptor_config.php @@ -0,0 +1,36 @@ + [ + 'testing.basicGrpcOnly.BasicGrpcOnly' => [ + 'AMethod' => [ + 'callType' => \Google\ApiCore\Call::UNARY_CALL, + 'responseType' => 'Testing\BasicGrpcOnly\Response', + ], + 'MethodWithArgs' => [ + 'callType' => \Google\ApiCore\Call::UNARY_CALL, + 'responseType' => 'Testing\BasicGrpcOnly\Response', + ], + ], + ], +]; diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_rest_client_config.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_rest_client_config.php new file mode 100644 index 00000000..66a59b31 --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/src/resources/basic_grpc_only_rest_client_config.php @@ -0,0 +1,39 @@ + [ + 'testing.basicGrpcOnly.BasicGrpcOnly' => [ + 'AMethod' => [ + 'method' => 'post', + 'uriTemplate' => '/path:aMethod', + 'body' => '*', + ], + 'MethodWithArgs' => [ + 'method' => 'post', + 'uriTemplate' => '/path:methodWithArgs', + 'body' => '*', + ], + ], + ], + 'numericEnums' => true, +]; diff --git a/tests/Unit/ProtoTests/BasicGrpcOnly/out/tests/Unit/Client/BasicGrpcOnlyClientTest.php b/tests/Unit/ProtoTests/BasicGrpcOnly/out/tests/Unit/Client/BasicGrpcOnlyClientTest.php new file mode 100644 index 00000000..510b0b3f --- /dev/null +++ b/tests/Unit/ProtoTests/BasicGrpcOnly/out/tests/Unit/Client/BasicGrpcOnlyClientTest.php @@ -0,0 +1,207 @@ +getMockBuilder(CredentialsWrapper::class)->disableOriginalConstructor()->getMock(); + } + + /** @return BasicGrpcOnlyClient */ + private function createClient(array $options = []) + { + $options += [ + 'credentials' => $this->createCredentials(), + ]; + return new BasicGrpcOnlyClient($options); + } + + /** @test */ + public function aMethodTest() + { + $transport = $this->createTransport(); + $gapicClient = $this->createClient([ + 'transport' => $transport, + ]); + $this->assertTrue($transport->isExhausted()); + // Mock response + $expectedResponse = new Response(); + $transport->addResponse($expectedResponse); + $request = new Request(); + $response = $gapicClient->aMethod($request); + $this->assertEquals($expectedResponse, $response); + $actualRequests = $transport->popReceivedCalls(); + $this->assertSame(1, count($actualRequests)); + $actualFuncCall = $actualRequests[0]->getFuncCall(); + $actualRequestObject = $actualRequests[0]->getRequestObject(); + $this->assertSame('/testing.basicGrpcOnly.BasicGrpcOnly/AMethod', $actualFuncCall); + $this->assertTrue($transport->isExhausted()); + } + + /** @test */ + public function aMethodExceptionTest() + { + $transport = $this->createTransport(); + $gapicClient = $this->createClient([ + 'transport' => $transport, + ]); + $this->assertTrue($transport->isExhausted()); + $status = new stdClass(); + $status->code = Code::DATA_LOSS; + $status->details = 'internal error'; + $expectedExceptionMessage = json_encode([ + 'message' => 'internal error', + 'code' => Code::DATA_LOSS, + 'status' => 'DATA_LOSS', + 'details' => [], + ], JSON_PRETTY_PRINT); + $transport->addResponse(null, $status); + $request = new Request(); + try { + $gapicClient->aMethod($request); + // If the $gapicClient method call did not throw, fail the test + $this->fail('Expected an ApiException, but no exception was thrown.'); + } catch (ApiException $ex) { + $this->assertEquals($status->code, $ex->getCode()); + $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); + } + // Call popReceivedCalls to ensure the stub is exhausted + $transport->popReceivedCalls(); + $this->assertTrue($transport->isExhausted()); + } + + /** @test */ + public function methodWithArgsTest() + { + $transport = $this->createTransport(); + $gapicClient = $this->createClient([ + 'transport' => $transport, + ]); + $this->assertTrue($transport->isExhausted()); + // Mock response + $expectedResponse = new Response(); + $transport->addResponse($expectedResponse); + // Mock request + $aString = 'aString-929604177'; + $partOfRequestA = []; + $request = (new RequestWithArgs()) + ->setAString($aString) + ->setPartOfRequestA($partOfRequestA); + $response = $gapicClient->methodWithArgs($request); + $this->assertEquals($expectedResponse, $response); + $actualRequests = $transport->popReceivedCalls(); + $this->assertSame(1, count($actualRequests)); + $actualFuncCall = $actualRequests[0]->getFuncCall(); + $actualRequestObject = $actualRequests[0]->getRequestObject(); + $this->assertSame('/testing.basicGrpcOnly.BasicGrpcOnly/MethodWithArgs', $actualFuncCall); + $actualValue = $actualRequestObject->getAString(); + $this->assertProtobufEquals($aString, $actualValue); + $actualValue = $actualRequestObject->getPartOfRequestA(); + $this->assertProtobufEquals($partOfRequestA, $actualValue); + $this->assertTrue($transport->isExhausted()); + } + + /** @test */ + public function methodWithArgsExceptionTest() + { + $transport = $this->createTransport(); + $gapicClient = $this->createClient([ + 'transport' => $transport, + ]); + $this->assertTrue($transport->isExhausted()); + $status = new stdClass(); + $status->code = Code::DATA_LOSS; + $status->details = 'internal error'; + $expectedExceptionMessage = json_encode([ + 'message' => 'internal error', + 'code' => Code::DATA_LOSS, + 'status' => 'DATA_LOSS', + 'details' => [], + ], JSON_PRETTY_PRINT); + $transport->addResponse(null, $status); + // Mock request + $aString = 'aString-929604177'; + $partOfRequestA = []; + $request = (new RequestWithArgs()) + ->setAString($aString) + ->setPartOfRequestA($partOfRequestA); + try { + $gapicClient->methodWithArgs($request); + // If the $gapicClient method call did not throw, fail the test + $this->fail('Expected an ApiException, but no exception was thrown.'); + } catch (ApiException $ex) { + $this->assertEquals($status->code, $ex->getCode()); + $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); + } + // Call popReceivedCalls to ensure the stub is exhausted + $transport->popReceivedCalls(); + $this->assertTrue($transport->isExhausted()); + } + + /** @test */ + public function aMethodAsyncTest() + { + $transport = $this->createTransport(); + $gapicClient = $this->createClient([ + 'transport' => $transport, + ]); + $this->assertTrue($transport->isExhausted()); + // Mock response + $expectedResponse = new Response(); + $transport->addResponse($expectedResponse); + $request = new Request(); + $response = $gapicClient->aMethodAsync($request)->wait(); + $this->assertEquals($expectedResponse, $response); + $actualRequests = $transport->popReceivedCalls(); + $this->assertSame(1, count($actualRequests)); + $actualFuncCall = $actualRequests[0]->getFuncCall(); + $actualRequestObject = $actualRequests[0]->getRequestObject(); + $this->assertSame('/testing.basicGrpcOnly.BasicGrpcOnly/AMethod', $actualFuncCall); + $this->assertTrue($transport->isExhausted()); + } +} diff --git a/tests/Unit/ProtoTests/ClientTest.php b/tests/Unit/ProtoTests/ClientTest.php index 91dac016..da897cdd 100644 --- a/tests/Unit/ProtoTests/ClientTest.php +++ b/tests/Unit/ProtoTests/ClientTest.php @@ -22,6 +22,7 @@ use Testing\BasicDiregapic\LibraryClient; use Google\ApiCore\InsecureCredentialsWrapper; use Google\ApiCore\ValidationException; +use Testing\BasicGrpcOnly\Client\BasicGrpcOnlyClient; final class ClientTest extends TestCase { @@ -35,4 +36,12 @@ public function testUnsupportedTransportThrowsException() 'credentials' => new InsecureCredentialsWrapper(), ]); } + + public function testGrpcOnlyClientThrowsExceptionForRestTransport() + { + $this->expectException(ValidationException::class); + $this->expectExceptionMessage('Unexpected transport option "rest". Supported transports: grpc, grpc-fallback'); + + $client = new BasicGrpcOnlyClient(['transport' => 'rest']); + } } diff --git a/tests/Unit/ProtoTests/GoldenUpdateMain.php b/tests/Unit/ProtoTests/GoldenUpdateMain.php index 2c2f81c6..fb61b3eb 100644 --- a/tests/Unit/ProtoTests/GoldenUpdateMain.php +++ b/tests/Unit/ProtoTests/GoldenUpdateMain.php @@ -98,6 +98,12 @@ class GoldenUpdateMain 16 => [ 'name' => 'BasicAutoPopulation', 'protoPath' => 'BasicAutoPopulation/basic-auto-population.proto' + ], + 17 => [ + 'name' => 'BasicGrpcOnlyClient', + 'protoPath' => 'BasicGrpcOnly/basicGrpcOnly.proto', + 'migrationMode' => MigrationMode::NEW_SURFACE_ONLY, + 'transport' => 'grpc' ] ];