From ceaaddbd08651df694e7b11834ae71556aa366aa Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 7 Oct 2020 16:18:54 -0700 Subject: [PATCH 1/9] fix: refactor requestBuilder into separate method in ServiceClientClassComposer --- .../composer/ServiceClientClassComposer.java | 138 +++--- .../api/generator/gapic/composer/BUILD.bazel | 4 +- .../ServiceClientClassComposerTest.java | 39 +- .../composer/goldens/IdentityClient.golden | 407 ++++++++++++++++++ .../api/generator/gapic/testdata/BUILD.bazel | 1 + .../generator/gapic/testdata/identity.proto | 192 +++++++++ 6 files changed, 705 insertions(+), 76 deletions(-) create mode 100644 src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden create mode 100644 src/test/java/com/google/api/generator/gapic/testdata/identity.proto diff --git a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java index 177fffb162..eb9d4abc99 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java @@ -64,6 +64,7 @@ import com.google.api.generator.gapic.model.MethodArgument; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.util.concurrent.MoreExecutors; @@ -90,6 +91,9 @@ public class ServiceClientClassComposer implements ClassComposer { private static final String PAGED_CALLABLE_NAME_PATTERN = "%sPagedCallable"; private static final String OPERATION_CALLABLE_NAME_PATTERN = "%sOperationCallable"; + private static final Reference LIST_REFERENCE = ConcreteReference.withClazz(List.class); + private static final Reference MAP_REFERENCE = ConcreteReference.withClazz(Map.class); + private enum CallableMethodKind { REGULAR, LRO, @@ -499,8 +503,6 @@ private static List createMethodVariants( } String methodInputTypeName = methodInputType.reference().name(); - Reference listRef = ConcreteReference.withClazz(List.class); - Reference mapRef = ConcreteReference.withClazz(Map.class); // Make the method signature order deterministic, which helps with unit testing and per-version // diffs. @@ -544,71 +546,12 @@ private static List createMethodVariants( .setIsDecl(true) .build(); - MethodInvocationExpr newBuilderExpr = - MethodInvocationExpr.builder() - .setMethodName("newBuilder") - .setStaticReferenceType(methodInputType) - .build(); - // TODO(miraleung): Handle nested arguments and descending setters here. - for (MethodArgument argument : signature) { - String argumentName = JavaStyle.toLowerCamelCase(argument.name()); - TypeNode argumentType = argument.type(); - String setterMethodVariantPattern = "set%s"; - if (TypeNode.isReferenceType(argumentType)) { - if (listRef.isSupertypeOrEquals(argumentType.reference())) { - setterMethodVariantPattern = "addAll%s"; - } else if (mapRef.isSupertypeOrEquals(argumentType.reference())) { - setterMethodVariantPattern = "putAll%s"; - } - } - String setterMethodName = - String.format(setterMethodVariantPattern, JavaStyle.toUpperCamelCase(argumentName)); - - Expr argVarExpr = - VariableExpr.withVariable( - Variable.builder().setName(argumentName).setType(argumentType).build()); - - if (argument.isResourceNameHelper()) { - MethodInvocationExpr isNullCheckExpr = - MethodInvocationExpr.builder() - .setStaticReferenceType(types.get("Objects")) - .setMethodName("isNull") - .setArguments(Arrays.asList(argVarExpr)) - .setReturnType(TypeNode.BOOLEAN) - .build(); - Expr nullExpr = ValueExpr.withValue(NullObjectValue.create()); - MethodInvocationExpr toStringExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(argVarExpr) - .setMethodName("toString") - .setReturnType(TypeNode.STRING) - .build(); - argVarExpr = - TernaryExpr.builder() - .setConditionExpr(isNullCheckExpr) - .setThenExpr(nullExpr) - .setElseExpr(toStringExpr) - .build(); - } + Expr requestBuilderExpr = createRequestBuilderExpr(method, signature, types); - newBuilderExpr = - MethodInvocationExpr.builder() - .setMethodName(setterMethodName) - .setArguments(Arrays.asList(argVarExpr)) - .setExprReferenceExpr(newBuilderExpr) - .build(); - } - - MethodInvocationExpr builderExpr = - MethodInvocationExpr.builder() - .setMethodName("build") - .setExprReferenceExpr(newBuilderExpr) - .setReturnType(methodInputType) - .build(); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() .setVariableExpr(requestVarExpr) - .setValueExpr(builderExpr) + .setValueExpr(requestBuilderExpr) .build(); List statements = Arrays.asList(ExprStatement.withExpr(requestAssignmentExpr)); @@ -1373,6 +1316,75 @@ private static ClassDefinition createNestedRpcFixedSizeCollectionClass( .build(); } + @VisibleForTesting + static Expr createRequestBuilderExpr( + Method method, List signature, Map types) { + TypeNode methodInputType = method.inputType(); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setMethodName("newBuilder") + .setStaticReferenceType(methodInputType) + .build(); + // TODO(miraleung): Handle nested arguments and descending setters here. + for (MethodArgument argument : signature) { + String argumentName = JavaStyle.toLowerCamelCase(argument.name()); + TypeNode argumentType = argument.type(); + String setterMethodVariantPattern = "set%s"; + if (TypeNode.isReferenceType(argumentType)) { + if (LIST_REFERENCE.isSupertypeOrEquals(argumentType.reference())) { + setterMethodVariantPattern = "addAll%s"; + } else if (MAP_REFERENCE.isSupertypeOrEquals(argumentType.reference())) { + setterMethodVariantPattern = "putAll%s"; + } + } + String setterMethodName = + String.format(setterMethodVariantPattern, JavaStyle.toUpperCamelCase(argumentName)); + + Expr argVarExpr = + VariableExpr.withVariable( + Variable.builder().setName(argumentName).setType(argumentType).build()); + + if (argument.isResourceNameHelper()) { + MethodInvocationExpr isNullCheckExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(types.get("Objects")) + .setMethodName("isNull") + .setArguments(Arrays.asList(argVarExpr)) + .setReturnType(TypeNode.BOOLEAN) + .build(); + Expr nullExpr = ValueExpr.withValue(NullObjectValue.create()); + MethodInvocationExpr toStringExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(argVarExpr) + .setMethodName("toString") + .setReturnType(TypeNode.STRING) + .build(); + argVarExpr = + TernaryExpr.builder() + .setConditionExpr(isNullCheckExpr) + .setThenExpr(nullExpr) + .setElseExpr(toStringExpr) + .build(); + } + + newBuilderExpr = + MethodInvocationExpr.builder() + .setMethodName(setterMethodName) + .setArguments(Arrays.asList(argVarExpr)) + .setExprReferenceExpr(newBuilderExpr) + .build(); + } + + MethodInvocationExpr builderExpr = + MethodInvocationExpr.builder() + .setMethodName("build") + .setExprReferenceExpr(newBuilderExpr) + .setReturnType(methodInputType) + .build(); + + return builderExpr; + } + private static Map createTypes( Service service, Map messageTypes) { Map types = new HashMap<>(); diff --git a/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel index d04f29e1c9..3a689014d3 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel @@ -11,6 +11,8 @@ UPDATE_GOLDENS_TESTS = [ "MockServiceClassComposerTest", "MockServiceImplClassComposerTest", "ResourceNameHelperClassComposerTest", + "ServiceClientClassComposerTest", + "ServiceClientTestClassComposerTest", "ServiceSettingsClassComposerTest", "ServiceStubSettingsClassComposerTest", "ServiceStubClassComposerTest", @@ -20,8 +22,6 @@ TESTS = UPDATE_GOLDENS_TESTS + [ "DefaultValueComposerTest", "ResourceNameTokenizerTest", "RetrySettingsComposerTest", - "ServiceClientClassComposerTest", - "ServiceClientTestClassComposerTest", ] TEST_DEPS = [ diff --git a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java index f0c0d70102..7e2f8d24d0 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java @@ -27,28 +27,22 @@ import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.showcase.v1beta1.EchoOuterClass; +import com.google.showcase.v1beta1.IdentityOuterClass; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.Before; import org.junit.Test; public class ServiceClientClassComposerTest { - private ServiceDescriptor echoService; - private FileDescriptor echoFileDescriptor; - - @Before - public void setUp() { - echoFileDescriptor = EchoOuterClass.getDescriptor(); - echoService = echoFileDescriptor.getServices().get(0); - assertEquals(echoService.getName(), "Echo"); - } - @Test public void generateServiceClasses() { + FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); + ServiceDescriptor echoService = echoFileDescriptor.getServices().get(0); + assertEquals(echoService.getName(), "Echo"); + Map messageTypes = Parser.parseMessages(echoFileDescriptor); Map resourceNames = Parser.parseResourceNames(echoFileDescriptor); Set outputResourceNames = new HashSet<>(); @@ -65,4 +59,27 @@ public void generateServiceClasses() { Path goldenFilePath = Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "EchoClient.golden"); assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + public void generateServiceClasses_methodSignatureHasNestedFields() { + FileDescriptor fileDescriptor = IdentityOuterClass.getDescriptor(); + ServiceDescriptor identityService = fileDescriptor.getServices().get(0); + assertEquals(identityService.getName(), "Identity"); + + Map messageTypes = Parser.parseMessages(fileDescriptor); + Map resourceNames = Parser.parseResourceNames(fileDescriptor); + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService(fileDescriptor, messageTypes, resourceNames, outputResourceNames); + + Service protoService = services.get(0); + GapicClass clazz = ServiceClientClassComposer.instance().generate(protoService, messageTypes); + + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + Utils.saveCodegenToFile(this.getClass(), "IdentityClient.golden", visitor.write()); + Path goldenFilePath = + Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "IdentityClient.golden"); + assertCodeEquals(goldenFilePath, visitor.write()); + } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden new file mode 100644 index 0000000000..0f6f1a418d --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden @@ -0,0 +1,407 @@ +package com.google.showcase.v1beta1; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.BetaApi; +import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.paging.AbstractFixedSizeCollection; +import com.google.api.gax.paging.AbstractPage; +import com.google.api.gax.paging.AbstractPagedListResponse; +import com.google.api.gax.rpc.PageContext; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.Empty; +import com.google.showcase.v1beta1.stub.IdentityStub; +import com.google.showcase.v1beta1.stub.IdentityStubSettings; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * This class provides the ability to make remote calls to the backing service through method calls + * that map to API methods. Sample code to get started: + * + *

Note: close() needs to be called on the echoClient object to clean up resources such as + * threads. In the example above, try-with-resources is used, which automatically calls close(). + * + *

The surface of this class includes several types of Java methods for each of the API's + * methods: + * + *

    + *
  1. A "flattened" method. With this type of method, the fields of the request type have been + * converted into function parameters. It may be the case that not all fields are available as + * parameters, and not every API method will have a flattened method entry point. + *
  2. A "request object" method. This type of method only takes one parameter, a request object, + * which must be constructed before the call. Not every API method will have a request object + * method. + *
  3. A "callable" method. This type of method takes no parameters and returns an immutable API + * callable object, which can be used to initiate calls to the service. + *
+ * + *

See the individual methods for example code. + * + *

Many parameters require resource names to be formatted in a particular way. To assist with + * these names, this class includes a format method for each type of name, and additionally a parse + * method to extract the individual identifiers contained within names that are returned. + * + *

This class can be customized by passing in a custom instance of IdentitySettings to create(). + * For example: + * + *

To customize credentials: + * + *

To customize the endpoint: + */ +@BetaApi +@Generated("by gapic-generator") +public class IdentityClient implements BackgroundResource { + private final IdentitySettings settings; + private final IdentityStub stub; + + /** Constructs an instance of EchoClient with default settings. */ + public static final IdentityClient create() throws IOException { + return create(IdentitySettings.newBuilder().build()); + } + + /** + * Constructs an instance of EchoClient, using the given settings. The channels are created based + * on the settings passed in, or defaults for any settings that are not set. + */ + public static final IdentityClient create(IdentitySettings settings) throws IOException { + return new IdentityClient(settings); + } + + /** + * Constructs an instance of EchoClient, using the given stub for making calls. This is for + * advanced usage - prefer using create(IdentitySettings). + */ + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + public static final IdentityClient create(IdentityStub stub) { + return new IdentityClient(stub); + } + + /** + * Constructs an instance of EchoClient, using the given settings. This is protected so that it is + * easy to make a subclass, but otherwise, the static factory methods should be preferred. + */ + protected IdentityClient(IdentitySettings settings) throws IOException { + this.settings = settings; + this.stub = ((IdentityStubSettings) settings.getStubSettings()).createStub(); + } + + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + protected IdentityClient(IdentityStub stub) { + this.settings = null; + this.stub = stub; + } + + public final IdentitySettings getSettings() { + return settings; + } + + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + public IdentityStub getStub() { + return stub; + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param parent + * @param display_name + * @param email + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser(String parent, String displayName, String email) { + CreateUserRequest request = + CreateUserRequest.newBuilder() + .setParent(parent) + .setDisplayName(displayName) + .setEmail(email) + .build(); + return createUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param parent + * @param display_name + * @param email + * @param age + * @param nickname + * @param enable_notifications + * @param height_feet + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser( + String parent, + String displayName, + String email, + int age, + String nickname, + boolean enableNotifications, + double heightFeet) { + CreateUserRequest request = + CreateUserRequest.newBuilder() + .setParent(parent) + .setDisplayName(displayName) + .setEmail(email) + .setAge(age) + .setNickname(nickname) + .setEnableNotifications(enableNotifications) + .setHeightFeet(heightFeet) + .build(); + return createUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser(CreateUserRequest request) { + return createUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable createUserCallable() { + return stub.createUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(UserName name) { + GetUserRequest request = + GetUserRequest.newBuilder().setName(Objects.isNull(name) ? null : name.toString()).build(); + return getUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(String name) { + GetUserRequest request = GetUserRequest.newBuilder().setName(name).build(); + return getUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(GetUserRequest request) { + return getUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable getUserCallable() { + return stub.getUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User updateUser(UpdateUserRequest request) { + return updateUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable updateUserCallable() { + return stub.updateUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(UserName name) { + DeleteUserRequest request = + DeleteUserRequest.newBuilder() + .setName(Objects.isNull(name) ? null : name.toString()) + .build(); + return deleteUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(String name) { + DeleteUserRequest request = DeleteUserRequest.newBuilder().setName(name).build(); + return deleteUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(DeleteUserRequest request) { + return deleteUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable deleteUserCallable() { + return stub.deleteUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListUsersPagedResponse listUsers(ListUsersRequest request) { + return listUsersPagedCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable listUsersPagedCallable() { + return stub.listUsersPagedCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable listUsersCallable() { + return stub.listUsersCallable(); + } + + @Override + public final void close() { + stub.close(); + } + + @Override + public void shutdown() { + stub.shutdown(); + } + + @Override + public boolean isShutdown() { + return stub.isShutdown(); + } + + @Override + public boolean isTerminated() { + return stub.isTerminated(); + } + + @Override + public void shutdownNow() { + stub.shutdownNow(); + } + + @Override + public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException { + return stub.awaitTermination(duration, unit); + } + + public static class ListUsersPagedResponse + extends AbstractPagedListResponse< + ListUsersRequest, ListUsersResponse, User, ListUsersPage, ListUsersFixedSizeCollection> { + + public static ApiFuture createAsync( + PageContext context, + ApiFuture futureResponse) { + ApiFuture futurePage = + ListUsersPage.createEmptyPage().createPageAsync(context, futureResponse); + return ApiFutures.transform( + futurePage, + new ApiFunction() { + @Override + public ListUsersPagedResponse apply(ListUsersPage input) { + return new ListUsersPagedResponse(input); + } + }, + MoreExecutors.directExecutor()); + } + + private ListUsersPagedResponse(ListUsersPage page) { + super(page, ListUsersFixedSizeCollection.createEmptyCollection()); + } + } + + public static class ListUsersPage + extends AbstractPage { + + private ListUsersPage( + PageContext context, + ListUsersResponse response) { + super(context, response); + } + + private static ListUsersPage createEmptyPage() { + return new ListUsersPage(null, null); + } + + @Override + protected ListUsersPage createPage( + PageContext context, + ListUsersResponse response) { + return new ListUsersPage(context, response); + } + + @Override + public ApiFuture createPageAsync( + PageContext context, + ApiFuture futureResponse) { + return super.createPageAsync(context, futureResponse); + } + } + + public static class ListUsersFixedSizeCollection + extends AbstractFixedSizeCollection< + ListUsersRequest, ListUsersResponse, User, ListUsersPage, ListUsersFixedSizeCollection> { + + private ListUsersFixedSizeCollection(List pages, int collectionSize) { + super(pages, collectionSize); + } + + private static ListUsersFixedSizeCollection createEmptyCollection() { + return new ListUsersFixedSizeCollection(null, 0); + } + + @Override + protected ListUsersFixedSizeCollection createCollection( + List pages, int collectionSize) { + return new ListUsersFixedSizeCollection(pages, collectionSize); + } + } +} diff --git a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel index a846eaf638..9682b5c414 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel @@ -32,6 +32,7 @@ proto_library( name = "showcase_proto", srcs = [ "echo.proto", + "identity.proto", "testing.proto", ], deps = [ diff --git a/src/test/java/com/google/api/generator/gapic/testdata/identity.proto b/src/test/java/com/google/api/generator/gapic/testdata/identity.proto new file mode 100644 index 0000000000..5ed47e8c59 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/testdata/identity.proto @@ -0,0 +1,192 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; + +package google.showcase.v1beta1; + +option go_package = "github.com/googleapis/gapic-showcase/server/genproto"; +option java_package = "com.google.showcase.v1beta1"; +option java_multiple_files = true; + +// A simple identity service. +service Identity { + // This service is meant to only run locally on the port 7469 (keypad digits + // for "show"). + option (google.api.default_host) = "localhost:7469"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform"; + + // Creates a user. + rpc CreateUser(CreateUserRequest) returns (User) { + option (google.api.http) = { + post: "/v1beta1/{parent=users}" + body: "*" + }; + option (google.api.method_signature) = + "parent,user.display_name,user.email"; + option (google.api.method_signature) = + "parent,user.display_name,user.email,user.age,user.nickname,user.enable_notifications,user.height_feet"; + } + + // Retrieves the User with the given uri. + rpc GetUser(GetUserRequest) returns (User) { + option (google.api.http) = { + get: "/v1beta1/{name=users/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Updates a user. + rpc UpdateUser(UpdateUserRequest) returns (User) { + option (google.api.http) = { + patch: "/v1beta1/{user.name=users/*}" + body: "*" + }; + } + + // Deletes a user, their profile, and all of their authored messages. + rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1beta1/{name=users/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists all users. + rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { + option (google.api.http) = { + get: "/v1beta1/users" + }; + } +} + +// A user. +message User { + option (google.api.resource) = { + type: "showcase.googleapis.com/User" + pattern: "users/{user}" + }; + + // The resource name of the user. + string name = 1; + + // The display_name of the user. + string display_name = 2 [(google.api.field_behavior) = REQUIRED]; + + // The email address of the user. + string email = 3 [(google.api.field_behavior) = REQUIRED]; + + // The timestamp at which the user was created. + google.protobuf.Timestamp create_time = 4 + [(google.api.field_behavior) = OUTPUT_ONLY]; + + // The latest timestamp at which the user was updated. + google.protobuf.Timestamp update_time = 5 + [(google.api.field_behavior) = OUTPUT_ONLY]; + + // The age of the use in years. + optional int32 age = 6; + + // The height of the user in feet. + optional double height_feet = 7; + + // The nickname of the user. + // + // (-- aip.dev/not-precedent: An empty string is a valid nickname. + // Ordinarily, proto3_optional should not be used on a `string` field. --) + optional string nickname = 8; + + // Enables the receiving of notifications. The default is true if unset. + // + // (-- aip.dev/not-precedent: The default for the feature is true. + // Ordinarily, the default for a `bool` field should be false. --) + optional bool enable_notifications = 9; +} + +// The request message for the google.showcase.v1beta1.Identity\CreateUser +// method. +message CreateUserRequest { + string parent = 1 [ + (google.api.resource_reference).child_type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; + // The user to create. + User user = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// The request message for the google.showcase.v1beta1.Identity\GetUser +// method. +message GetUserRequest { + // The resource name of the requested user. + string name = 1 [ + (google.api.resource_reference).type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; +} + +// The request message for the google.showcase.v1beta1.Identity\UpdateUser +// method. +message UpdateUserRequest { + // The user to update. + User user = 1; + + // The field mask to determine wich fields are to be updated. If empty, the + // server will assume all fields are to be updated. + google.protobuf.FieldMask update_mask = 2; +} + +// The request message for the google.showcase.v1beta1.Identity\DeleteUser +// method. +message DeleteUserRequest { + // The resource name of the user to delete. + string name = 1 [ + (google.api.resource_reference).type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; +} + +// The request message for the google.showcase.v1beta1.Identity\ListUsers +// method. +message ListUsersRequest { + // The maximum number of users to return. Server may return fewer users + // than requested. If unspecified, server will pick an appropriate default. + int32 page_size = 1; + + // The value of google.showcase.v1beta1.ListUsersResponse.next_page_token + // returned from the previous call to + // `google.showcase.v1beta1.Identity\ListUsers` method. + string page_token = 2; +} + +// The response message for the google.showcase.v1beta1.Identity\ListUsers +// method. +message ListUsersResponse { + // The list of users. + repeated User users = 1; + + // A token to retrieve next page of results. + // Pass this value in ListUsersRequest.page_token field in the subsequent + // call to `google.showcase.v1beta1.Message\ListUsers` method to retrieve the + // next page of results. + string next_page_token = 2; +} From bdcb62ecd23604ae07d47501503866e8c77e0d0c Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 13:19:44 -0700 Subject: [PATCH 2/9] feat: add varargs to AnonClass and ref setter methods --- .../api/generator/engine/ast/AnonymousClassExpr.java | 5 +++++ .../google/api/generator/engine/ast/ConcreteReference.java | 7 ++++++- .../google/api/generator/engine/ast/VaporReference.java | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java b/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java index 7cbce07ff0..e4ddc7e11d 100644 --- a/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java +++ b/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -45,6 +46,10 @@ public static Builder builder() { public abstract static class Builder { public abstract Builder setType(TypeNode type); + public Builder setMethods(MethodDefinition... methods) { + return setMethods(Arrays.asList(methods)); + } + public abstract Builder setMethods(List methods); public abstract Builder setStatements(List statements); diff --git a/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java b/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java index 7d37a02417..58494fe7a5 100644 --- a/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java +++ b/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java @@ -16,6 +16,7 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.annotation.Nullable; @@ -210,7 +211,11 @@ public abstract static class Builder { public abstract Builder setWildcardUpperBound(Reference reference); - public abstract Builder setGenerics(List clazzes); + public Builder setGenerics(Reference... references) { + return setGenerics(Arrays.asList(references)); + } + + public abstract Builder setGenerics(List references); public abstract Builder setIsStaticImport(boolean isStaticImport); diff --git a/src/main/java/com/google/api/generator/engine/ast/VaporReference.java b/src/main/java/com/google/api/generator/engine/ast/VaporReference.java index c3b237bdf3..cd9361ebe3 100644 --- a/src/main/java/com/google/api/generator/engine/ast/VaporReference.java +++ b/src/main/java/com/google/api/generator/engine/ast/VaporReference.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.annotation.Nullable; @@ -146,6 +147,10 @@ public abstract static class Builder { public abstract Builder setUseFullName(boolean useFullName); + public Builder setGenerics(Reference... references) { + return setGenerics(Arrays.asList(references)); + } + public abstract Builder setGenerics(List clazzes); public abstract Builder setEnclosingClassName(String enclosingClassName); From e15e1157ac8e8d4f2273c83a919a5c064ff62084 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 13:22:32 -0700 Subject: [PATCH 3/9] feat: add HTTP annotation parsing/validation --- .../api/generator/engine/ast/TypeNode.java | 4 + .../api/generator/gapic/model/Method.java | 11 ++ .../gapic/protoparser/HttpRuleParser.java | 129 ++++++++++++++++++ .../generator/gapic/protoparser/Parser.java | 8 ++ .../generator/gapic/protoparser/BUILD.bazel | 1 + .../gapic/protoparser/HttpRuleParserTest.java | 73 ++++++++++ 6 files changed, 226 insertions(+) create mode 100644 src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java create mode 100644 src/test/java/com/google/api/generator/gapic/protoparser/HttpRuleParserTest.java diff --git a/src/main/java/com/google/api/generator/engine/ast/TypeNode.java b/src/main/java/com/google/api/generator/engine/ast/TypeNode.java index 9505cbb8cc..49fa35aaac 100644 --- a/src/main/java/com/google/api/generator/engine/ast/TypeNode.java +++ b/src/main/java/com/google/api/generator/engine/ast/TypeNode.java @@ -186,6 +186,10 @@ public boolean isPrimitiveType() { return isPrimitiveType(typeKind()); } + public boolean isProtoPrimitiveType() { + return isPrimitiveType() || this.equals(TypeNode.STRING); + } + public boolean isSupertypeOrEquals(TypeNode other) { boolean oneTypeIsNull = this.equals(TypeNode.NULL) ^ other.equals(TypeNode.NULL); return !isPrimitiveType() diff --git a/src/main/java/com/google/api/generator/gapic/model/Method.java b/src/main/java/com/google/api/generator/gapic/model/Method.java index 30e94c9ad5..2d78b5f941 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Method.java +++ b/src/main/java/com/google/api/generator/gapic/model/Method.java @@ -45,6 +45,10 @@ public enum Stream { @Nullable public abstract String description(); + // TODO(miraleung): May need to change this to MethodArgument, Field, or some new struct + // HttpBinding pending dotted reference support. + public abstract List httpBindings(); + // Example from Expand in echo.proto: Thet TypeNodes that map to // [["content", "error"], ["content", "error", "info"]]. public abstract ImmutableList> methodSignatures(); @@ -57,10 +61,15 @@ public boolean hasDescription() { return description() != null; } + public boolean hasHttpBindings() { + return !httpBindings().isEmpty(); + } + public static Builder builder() { return new AutoValue_Method.Builder() .setStream(Stream.NONE) .setMethodSignatures(ImmutableList.of()) + .setHttpBindings(ImmutableList.of()) .setIsPaged(false); } @@ -91,6 +100,8 @@ public abstract static class Builder { public abstract Builder setDescription(String description); + public abstract Builder setHttpBindings(List httpBindings); + public abstract Builder setMethodSignatures(List> methodSignature); public abstract Builder setIsPaged(boolean isPaged); diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java b/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java new file mode 100644 index 0000000000..e48344afde --- /dev/null +++ b/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java @@ -0,0 +1,129 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.gapic.protoparser; + +import com.google.api.AnnotationsProto; +import com.google.api.HttpRule; +import com.google.api.HttpRule.PatternCase; +import com.google.api.generator.gapic.model.Field; +import com.google.api.generator.gapic.model.Message; +import com.google.api.pathtemplate.PathTemplate; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.protobuf.DescriptorProtos.MethodOptions; +import com.google.protobuf.Descriptors.MethodDescriptor; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class HttpRuleParser { + private static final String ASTERISK = "*"; + + public static Optional> parseHttpBindings( + MethodDescriptor protoMethod, Message inputMessage, Map messageTypes) { + MethodOptions methodOptions = protoMethod.getOptions(); + if (!methodOptions.hasExtension(AnnotationsProto.http)) { + return Optional.empty(); + } + + HttpRule httpRule = methodOptions.getExtension(AnnotationsProto.http); + + // Body validation. + if (!Strings.isNullOrEmpty(httpRule.getBody()) && !httpRule.getBody().equals(ASTERISK)) { + checkHttpFieldIsValid(httpRule.getBody(), inputMessage, true); + } + + // Get pattern. + List bindings = getPatternBindings(httpRule); + if (bindings.isEmpty()) { + return Optional.empty(); + } + + // Binding validation. + for (String binding : bindings) { + // Handle foo.bar cases by descending into the subfields. + String[] descendantBindings = binding.split("\\."); + Message containingMessage = inputMessage; + for (int i = 0; i < descendantBindings.length; i++) { + String subField = descendantBindings[i]; + if (i < descendantBindings.length - 1) { + Field field = containingMessage.fieldMap().get(subField); + containingMessage = messageTypes.get(field.type().reference().name()); + } else { + checkHttpFieldIsValid(subField, containingMessage, false); + } + } + } + + return Optional.of(bindings); + } + + private static List getPatternBindings(HttpRule httpRule) { + String pattern = null; + // Assign a temp variable to prevent the formatter from removing the import. + PatternCase patternCase = httpRule.getPatternCase(); + switch (patternCase) { + case GET: + pattern = httpRule.getGet(); + break; + case PUT: + pattern = httpRule.getPut(); + break; + case POST: + pattern = httpRule.getPost(); + break; + case DELETE: + pattern = httpRule.getDelete(); + break; + case PATCH: + pattern = httpRule.getPatch(); + break; + case CUSTOM: // Invalid pattern. + // Fall through. + default: + return Collections.emptyList(); + } + + PathTemplate template = PathTemplate.create(pattern); + List bindings = new ArrayList(template.vars()); + Collections.sort(bindings); + return bindings; + } + + private static void checkHttpFieldIsValid(String binding, Message inputMessage, boolean isBody) { + Preconditions.checkState( + !Strings.isNullOrEmpty(binding), + String.format("DEL: Null or empty binding for " + inputMessage.name())); + Preconditions.checkState( + inputMessage.fieldMap().containsKey(binding), + String.format( + "Expected message %s to contain field %s but none found", + inputMessage.name(), binding)); + Field field = inputMessage.fieldMap().get(binding); + boolean fieldCondition = !field.isRepeated(); + if (!isBody) { + fieldCondition &= field.type().isProtoPrimitiveType(); + } + String messageFormat = + "Expected a non-repeated " + + (isBody ? "" : "primitive ") + + "type for field %s in message %s but got type %s"; + Preconditions.checkState( + fieldCondition, + String.format(messageFormat, field.name(), inputMessage.name(), field.type())); + } +} diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index 43e7e7c435..98e7fe5f5d 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -276,6 +277,12 @@ static List parseMethods( } } + Optional> httpBindingsOpt = + HttpRuleParser.parseHttpBindings( + protoMethod, messageTypes.get(inputType.reference().name()), messageTypes); + List httpBindings = + httpBindingsOpt.isPresent() ? httpBindingsOpt.get() : Collections.emptyList(); + methods.add( methodBuilder .setName(protoMethod.getName()) @@ -292,6 +299,7 @@ static List parseMethods( messageTypes, resourceNames, outputArgResourceNames)) + .setHttpBindings(httpBindings) .setIsPaged(parseIsPaged(protoMethod, messageTypes)) .build()); diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/protoparser/BUILD.bazel index cc3063d4db..a7df4ab20b 100644 --- a/src/test/java/com/google/api/generator/gapic/protoparser/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/protoparser/BUILD.bazel @@ -4,6 +4,7 @@ package(default_visibility = ["//visibility:public"]) TESTS = [ "BatchingSettingsConfigParserTest", + "HttpRuleParserTest", "MethodSignatureParserTest", "ParserTest", "PluginArgumentParserTest", diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/HttpRuleParserTest.java b/src/test/java/com/google/api/generator/gapic/protoparser/HttpRuleParserTest.java new file mode 100644 index 0000000000..4f20e23a33 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/protoparser/HttpRuleParserTest.java @@ -0,0 +1,73 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.gapic.protoparser; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertThrows; + +import com.google.api.generator.gapic.model.Message; +import com.google.protobuf.Descriptors.FileDescriptor; +import com.google.protobuf.Descriptors.MethodDescriptor; +import com.google.protobuf.Descriptors.ServiceDescriptor; +import com.google.showcase.v1beta1.TestingOuterClass; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.junit.Test; + +public class HttpRuleParserTest { + @Test + public void parseHttpAnnotation_basic() { + FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor(); + ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0); + assertEquals(testingService.getName(), "Testing"); + + Map messages = Parser.parseMessages(testingFileDescriptor); + + // CreateSession method. + MethodDescriptor rpcMethod = testingService.getMethods().get(0); + Message inputMessage = messages.get("CreateSessionRequest"); + Optional> httpBindingsOpt = + HttpRuleParser.parseHttpBindings(rpcMethod, inputMessage, messages); + assertFalse(httpBindingsOpt.isPresent()); + + // VerityTest method. + rpcMethod = testingService.getMethods().get(testingService.getMethods().size() - 1); + inputMessage = messages.get("VerifyTestRequest"); + httpBindingsOpt = HttpRuleParser.parseHttpBindings(rpcMethod, inputMessage, messages); + assertTrue(httpBindingsOpt.isPresent()); + assertThat(httpBindingsOpt.get()).containsExactly("name"); + } + + @Test + public void parseHttpAnnotation_missingFieldFromMessage() { + FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor(); + ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0); + assertEquals(testingService.getName(), "Testing"); + + Map messages = Parser.parseMessages(testingFileDescriptor); + + // VerityTest method. + MethodDescriptor rpcMethod = + testingService.getMethods().get(testingService.getMethods().size() - 1); + Message inputMessage = messages.get("CreateSessionRequest"); + assertThrows( + IllegalStateException.class, + () -> HttpRuleParser.parseHttpBindings(rpcMethod, inputMessage, messages)); + } +} From 28d3b3c9300dffdc7defd81f17d2bef9335bef8f Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 13:23:48 -0700 Subject: [PATCH 4/9] feat: Generate RequestParamsExtractor in GrpcServiceStub --- .../GrpcServiceStubClassComposer.java | 164 ++++++-- .../GrpcServiceStubClassComposerTest.java | 40 +- .../composer/goldens/GrpcTestingStub.golden | 355 ++++++++++++++++++ test/integration/BUILD.bazel | 3 +- 4 files changed, 528 insertions(+), 34 deletions(-) create mode 100644 src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcTestingStub.golden diff --git a/src/main/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposer.java index 73f0780209..0d688dfc47 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposer.java @@ -22,9 +22,11 @@ import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ClientStreamingCallable; import com.google.api.gax.rpc.OperationCallable; +import com.google.api.gax.rpc.RequestParamsExtractor; import com.google.api.gax.rpc.ServerStreamingCallable; import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; +import com.google.api.generator.engine.ast.AnonymousClassExpr; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ClassDefinition; import com.google.api.generator.engine.ast.ConcreteReference; @@ -51,6 +53,8 @@ import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import com.google.longrunning.Operation; import com.google.longrunning.stub.GrpcOperationsStub; import io.grpc.MethodDescriptor; @@ -90,7 +94,7 @@ public class GrpcServiceStubClassComposer implements ClassComposer { private static final GrpcServiceStubClassComposer INSTANCE = new GrpcServiceStubClassComposer(); - private static final Map staticTypes = createStaticTypes(); + private static final Map STATIC_TYPES = createStaticTypes(); private GrpcServiceStubClassComposer() {} @@ -117,21 +121,21 @@ public GapicClass generate(Service service, Map ignore) { VariableExpr.withVariable( Variable.builder() .setName(BACKGROUND_RESOURCES_MEMBER_NAME) - .setType(staticTypes.get("BackgroundResource")) + .setType(STATIC_TYPES.get("BackgroundResource")) .build())); classMemberVarExprs.put( OPERATIONS_STUB_MEMBER_NAME, VariableExpr.withVariable( Variable.builder() .setName(OPERATIONS_STUB_MEMBER_NAME) - .setType(staticTypes.get("GrpcOperationsStub")) + .setType(STATIC_TYPES.get("GrpcOperationsStub")) .build())); classMemberVarExprs.put( CALLABLE_FACTORY_MEMBER_NAME, VariableExpr.withVariable( Variable.builder() .setName(CALLABLE_FACTORY_MEMBER_NAME) - .setType(staticTypes.get("GrpcStubCallableFactory")) + .setType(STATIC_TYPES.get("GrpcStubCallableFactory")) .build())); List classStatements = @@ -196,7 +200,7 @@ private static Statement createMethodDescriptorVariableDecl( MethodInvocationExpr methodDescriptorMaker = MethodInvocationExpr.builder() .setMethodName("newBuilder") - .setStaticReferenceType(staticTypes.get("MethodDescriptor")) + .setStaticReferenceType(STATIC_TYPES.get("MethodDescriptor")) .setGenerics(methodDescriptorVarExpr.variable().type().reference().generics()) .build(); @@ -226,7 +230,7 @@ private static Statement createMethodDescriptorVariableDecl( Function protoUtilsMarshallerFn = m -> MethodInvocationExpr.builder() - .setStaticReferenceType(staticTypes.get("ProtoUtils")) + .setStaticReferenceType(STATIC_TYPES.get("ProtoUtils")) .setMethodName("marshaller") .setArguments(Arrays.asList(m)) .build(); @@ -374,7 +378,7 @@ private static Map createCallableClassMembers( private static List createClassAnnotations() { return Arrays.asList( AnnotationNode.builder() - .setType(staticTypes.get("Generated")) + .setType(STATIC_TYPES.get("Generated")) .setDescription("by gapic-generator-java") .build()); } @@ -430,7 +434,7 @@ private static List createStaticCreatorMethods( VariableExpr.withVariable( Variable.builder().setName("settings").setType(stubSettingsType).build()); - TypeNode clientContextType = staticTypes.get("ClientContext"); + TypeNode clientContextType = STATIC_TYPES.get("ClientContext"); VariableExpr clientContextVarExpr = VariableExpr.withVariable( Variable.builder().setName("clientContext").setType(clientContextType).build()); @@ -439,7 +443,7 @@ private static List createStaticCreatorMethods( VariableExpr.withVariable( Variable.builder() .setName("callableFactory") - .setType(staticTypes.get("GrpcStubCallableFactory")) + .setType(STATIC_TYPES.get("GrpcStubCallableFactory")) .build()); MethodInvocationExpr clientContextCreateMethodExpr = @@ -492,7 +496,7 @@ private static List createConstructorMethods( VariableExpr.withVariable( Variable.builder().setName("settings").setType(stubSettingsType).build()); - TypeNode clientContextType = staticTypes.get("ClientContext"); + TypeNode clientContextType = STATIC_TYPES.get("ClientContext"); VariableExpr clientContextVarExpr = VariableExpr.withVariable( Variable.builder().setName("clientContext").setType(clientContextType).build()); @@ -501,7 +505,7 @@ private static List createConstructorMethods( VariableExpr.withVariable( Variable.builder() .setName("callableFactory") - .setType(staticTypes.get("GrpcStubCallableFactory")) + .setType(STATIC_TYPES.get("GrpcStubCallableFactory")) .build()); TypeNode thisClassType = types.get(getThisClassName(service.name())); @@ -562,7 +566,7 @@ private static List createConstructorMethods( operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) .setValueExpr( MethodInvocationExpr.builder() - .setStaticReferenceType(staticTypes.get("GrpcOperationsStub")) + .setStaticReferenceType(STATIC_TYPES.get("GrpcOperationsStub")) .setMethodName("create") .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) .setReturnType(operationsStubClassVarExpr.type()) @@ -602,6 +606,7 @@ private static List createConstructorMethods( .map( m -> createTransportSettingsInitExpr( + m, javaStyleMethodNameToTransportSettingsVarExprs.get( JavaStyle.toLowerCamelCase(m.name())), protoMethodNameToDescriptorVarExprs.get(m.name()))) @@ -644,7 +649,7 @@ private static List createConstructorMethods( backgroundResourcesVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) .setValueExpr( NewObjectExpr.builder() - .setType(staticTypes.get("BackgroundResourceAggregation")) + .setType(STATIC_TYPES.get("BackgroundResourceAggregation")) .setArguments(Arrays.asList(getBackgroundResourcesMethodExpr)) .build()) .build()); @@ -662,10 +667,10 @@ private static List createConstructorMethods( } private static Expr createTransportSettingsInitExpr( - VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) { + Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) { MethodInvocationExpr callSettingsBuilderExpr = MethodInvocationExpr.builder() - .setStaticReferenceType(staticTypes.get("GrpcCallSettings")) + .setStaticReferenceType(STATIC_TYPES.get("GrpcCallSettings")) .setGenerics(transportSettingsVarExpr.type().reference().generics()) .setMethodName("newBuilder") .build(); @@ -675,6 +680,16 @@ private static Expr createTransportSettingsInitExpr( .setMethodName("setMethodDescriptor") .setArguments(Arrays.asList(methodDescriptorVarExpr)) .build(); + + if (method.hasHttpBindings()) { + callSettingsBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(callSettingsBuilderExpr) + .setMethodName("setParamsExtractor") + .setArguments(createRequestParamsExtractorAnonClass(method)) + .build(); + } + callSettingsBuilderExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(callSettingsBuilderExpr) @@ -687,6 +702,111 @@ private static Expr createTransportSettingsInitExpr( .build(); } + private static AnonymousClassExpr createRequestParamsExtractorAnonClass(Method method) { + Preconditions.checkState( + method.hasHttpBindings(), String.format("Method %s has no HTTP binding", method.name())); + + TypeNode paramsVarType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(ImmutableMap.Builder.class) + .setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference()) + .build()); + VariableExpr paramsVarExpr = + VariableExpr.withVariable( + Variable.builder().setName("params").setType(paramsVarType).build()); + VariableExpr reqeustVarExpr = + VariableExpr.withVariable( + Variable.builder().setName("request").setType(method.inputType()).build()); + + Expr paramsAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(paramsVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr( + MethodInvocationExpr.builder() + .setStaticReferenceType(STATIC_TYPES.get("ImmutableMap")) + .setMethodName("builder") + .setReturnType(paramsVarType) + .build()) + .build(); + List bodyExprs = new ArrayList<>(); + bodyExprs.add(paramsAssignExpr); + + VariableExpr requestVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(method.inputType()).setName("request").build()); + + for (String httpBindingFieldName : method.httpBindings()) { + // Handle foo.bar cases by descending into the subfields. + MethodInvocationExpr.Builder requestFieldGetterExprBuilder = + MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr); + String[] descendantFields = httpBindingFieldName.split("\\."); + for (int i = 0; i < descendantFields.length; i++) { + String currFieldName = descendantFields[i]; + String bindingFieldMethodName = + String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName)); + requestFieldGetterExprBuilder = + requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName); + if (i < descendantFields.length - 1) { + requestFieldGetterExprBuilder = + MethodInvocationExpr.builder() + .setExprReferenceExpr(requestFieldGetterExprBuilder.build()); + } + } + + MethodInvocationExpr requestBuilderExpr = requestFieldGetterExprBuilder.build(); + Expr valueOfExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(TypeNode.STRING) + .setMethodName("valueOf") + .setArguments(requestBuilderExpr) + .build(); + + Expr paramsPutExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(paramsVarExpr) + .setMethodName("put") + .setArguments( + ValueExpr.withValue(StringObjectValue.withValue(httpBindingFieldName)), + valueOfExpr) + .build(); + bodyExprs.add(paramsPutExpr); + } + + TypeNode returnType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(Map.class) + .setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference()) + .build()); + Expr returnExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(paramsVarExpr) + .setMethodName("build") + .setReturnType(returnType) + .build(); + + MethodDefinition extractMethod = + MethodDefinition.builder() + .setIsOverride(true) + .setScope(ScopeNode.PUBLIC) + .setReturnType(returnType) + .setName("extract") + .setArguments(requestVarExpr.toBuilder().setIsDecl(true).build()) + .setBody( + bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList())) + .setReturnExpr(returnExpr) + .build(); + + TypeNode anonClassType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(RequestParamsExtractor.class) + .setGenerics(method.inputType().reference()) + .build()); + return AnonymousClassExpr.builder().setType(anonClassType).setMethods(extractMethod).build(); + } + private static Expr createCallableInitExpr( String callableVarName, VariableExpr callableVarExpr, @@ -845,7 +965,7 @@ private static List createStubOverrideMethods( VariableExpr.withVariable( Variable.builder().setName("duration").setType(TypeNode.LONG).build()), VariableExpr.withVariable( - Variable.builder().setName("unit").setType(staticTypes.get("TimeUnit")).build())); + Variable.builder().setName("unit").setType(STATIC_TYPES.get("TimeUnit")).build())); javaMethods.add( methodMakerStarterFn .apply("awaitTermination") @@ -854,7 +974,7 @@ private static List createStubOverrideMethods( awaitTerminationArgs.stream() .map(v -> v.toBuilder().setIsDecl(true).build()) .collect(Collectors.toList())) - .setThrowsExceptions(Arrays.asList(staticTypes.get("InterruptedException"))) + .setThrowsExceptions(Arrays.asList(STATIC_TYPES.get("InterruptedException"))) .setReturnExpr( MethodInvocationExpr.builder() .setExprReferenceExpr(backgroundResourcesVarExpr) @@ -881,12 +1001,14 @@ private static Map createStaticTypes() { GrpcCallSettings.class, GrpcOperationsStub.class, GrpcStubCallableFactory.class, + ImmutableMap.class, InterruptedException.class, IOException.class, MethodDescriptor.class, Operation.class, OperationCallable.class, ProtoUtils.class, + RequestParamsExtractor.class, ServerStreamingCallable.class, TimeUnit.class, UnaryCallable.class); @@ -934,16 +1056,16 @@ private static Map createDynamicTypes(Service service, String } private static TypeNode getCallableType(Method protoMethod) { - TypeNode callableType = staticTypes.get("UnaryCallable"); + TypeNode callableType = STATIC_TYPES.get("UnaryCallable"); switch (protoMethod.stream()) { case CLIENT: - callableType = staticTypes.get("ClientStreamingCallable"); + callableType = STATIC_TYPES.get("ClientStreamingCallable"); break; case SERVER: - callableType = staticTypes.get("ServerStreamingCallable"); + callableType = STATIC_TYPES.get("ServerStreamingCallable"); break; case BIDI: - callableType = staticTypes.get("BidiStreamingCallable"); + callableType = STATIC_TYPES.get("BidiStreamingCallable"); break; case NONE: // Fall through diff --git a/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java index e3f63dcaa8..402d94450a 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java @@ -27,28 +27,22 @@ import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.showcase.v1beta1.EchoOuterClass; +import com.google.showcase.v1beta1.TestingOuterClass; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.Before; import org.junit.Test; public class GrpcServiceStubClassComposerTest { - private ServiceDescriptor echoService; - private FileDescriptor echoFileDescriptor; - - @Before - public void setUp() { - echoFileDescriptor = EchoOuterClass.getDescriptor(); - echoService = echoFileDescriptor.getServices().get(0); + @Test + public void generateGrpcServiceStubClass_simple() { + FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); + ServiceDescriptor echoService = echoFileDescriptor.getServices().get(0); assertEquals(echoService.getName(), "Echo"); - } - @Test - public void generateServiceClasses() { Map messageTypes = Parser.parseMessages(echoFileDescriptor); Map resourceNames = Parser.parseResourceNames(echoFileDescriptor); Set outputResourceNames = new HashSet<>(); @@ -64,4 +58,28 @@ public void generateServiceClasses() { Path goldenFilePath = Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "GrpcEchoStub.golden"); Assert.assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + public void generateGrpcServiceStubClass_httpBindings() { + FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor(); + ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0); + assertEquals(testingService.getName(), "Testing"); + + Map messageTypes = Parser.parseMessages(testingFileDescriptor); + Map resourceNames = Parser.parseResourceNames(testingFileDescriptor); + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService( + testingFileDescriptor, messageTypes, resourceNames, outputResourceNames); + Service testingProtoService = services.get(0); + GapicClass clazz = + GrpcServiceStubClassComposer.instance().generate(testingProtoService, messageTypes); + + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + Utils.saveCodegenToFile(this.getClass(), "GrpcTestingStub.golden", visitor.write()); + Path goldenFilePath = + Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "GrpcTestingStub.golden"); + Assert.assertCodeEquals(goldenFilePath, visitor.write()); + } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcTestingStub.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcTestingStub.golden new file mode 100644 index 0000000000..8ab8396bb9 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcTestingStub.golden @@ -0,0 +1,355 @@ +package com.google.showcase.v1beta1.stub; + +import static com.google.showcase.v1beta1.TestingClient.ListSessionsPagedResponse; +import static com.google.showcase.v1beta1.TestingClient.ListTestsPagedResponse; + +import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.core.BackgroundResourceAggregation; +import com.google.api.gax.grpc.GrpcCallSettings; +import com.google.api.gax.grpc.GrpcStubCallableFactory; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.RequestParamsExtractor; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.common.collect.ImmutableMap; +import com.google.longrunning.stub.GrpcOperationsStub; +import com.google.protobuf.Empty; +import com.google.showcase.v1beta1.CreateSessionRequest; +import com.google.showcase.v1beta1.DeleteSessionRequest; +import com.google.showcase.v1beta1.DeleteTestRequest; +import com.google.showcase.v1beta1.GetSessionRequest; +import com.google.showcase.v1beta1.ListSessionsRequest; +import com.google.showcase.v1beta1.ListSessionsResponse; +import com.google.showcase.v1beta1.ListTestsRequest; +import com.google.showcase.v1beta1.ListTestsResponse; +import com.google.showcase.v1beta1.ReportSessionRequest; +import com.google.showcase.v1beta1.ReportSessionResponse; +import com.google.showcase.v1beta1.Session; +import com.google.showcase.v1beta1.VerifyTestRequest; +import com.google.showcase.v1beta1.VerifyTestResponse; +import io.grpc.MethodDescriptor; +import io.grpc.protobuf.ProtoUtils; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * gRPC stub implementation for the Testing service API. + * + *

This class is for advanced usage and reflects the underlying API directly. + */ +@Generated("by gapic-generator-java") +public class GrpcTestingStub extends TestingStub { + private static final MethodDescriptor + createSessionMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/CreateSession") + .setRequestMarshaller( + ProtoUtils.marshaller(CreateSessionRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Session.getDefaultInstance())) + .build(); + + private static final MethodDescriptor getSessionMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/GetSession") + .setRequestMarshaller(ProtoUtils.marshaller(GetSessionRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Session.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + listSessionsMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/ListSessions") + .setRequestMarshaller(ProtoUtils.marshaller(ListSessionsRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(ListSessionsResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor deleteSessionMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/DeleteSession") + .setRequestMarshaller(ProtoUtils.marshaller(DeleteSessionRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + reportSessionMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/ReportSession") + .setRequestMarshaller( + ProtoUtils.marshaller(ReportSessionRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(ReportSessionResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + listTestsMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/ListTests") + .setRequestMarshaller(ProtoUtils.marshaller(ListTestsRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(ListTestsResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor deleteTestMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/DeleteTest") + .setRequestMarshaller(ProtoUtils.marshaller(DeleteTestRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + verifyTestMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.showcase.v1beta1.Testing/VerifyTest") + .setRequestMarshaller(ProtoUtils.marshaller(VerifyTestRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(VerifyTestResponse.getDefaultInstance())) + .build(); + + private final UnaryCallable createSessionCallable; + private final UnaryCallable getSessionCallable; + private final UnaryCallable listSessionsCallable; + private final UnaryCallable + listSessionsPagedCallable; + private final UnaryCallable deleteSessionCallable; + private final UnaryCallable reportSessionCallable; + private final UnaryCallable listTestsCallable; + private final UnaryCallable listTestsPagedCallable; + private final UnaryCallable deleteTestCallable; + private final UnaryCallable verifyTestCallable; + + private final BackgroundResource backgroundResources; + private final GrpcOperationsStub operationsStub; + private final GrpcStubCallableFactory callableFactory; + + public static final GrpcTestingStub create(TestingStubSettings settings) throws IOException { + return new GrpcTestingStub(settings, ClientContext.create(settings)); + } + + public static final GrpcTestingStub create(ClientContext clientContext) throws IOException { + return new GrpcTestingStub(TestingStubSettings.newBuilder().build(), clientContext); + } + + public static final GrpcTestingStub create( + ClientContext clientContext, GrpcStubCallableFactory callableFactory) throws IOException { + return new GrpcTestingStub( + TestingStubSettings.newBuilder().build(), clientContext, callableFactory); + } + + protected GrpcTestingStub(TestingStubSettings settings, ClientContext clientContext) + throws IOException { + this(settings, clientContext, new GrpcTestingCallableFactory()); + } + + protected GrpcTestingStub( + TestingStubSettings settings, + ClientContext clientContext, + GrpcStubCallableFactory callableFactory) + throws IOException { + this.callableFactory = callableFactory; + this.operationsStub = GrpcOperationsStub.create(clientContext, callableFactory); + + GrpcCallSettings createSessionTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(createSessionMethodDescriptor) + .build(); + GrpcCallSettings getSessionTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(getSessionMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(GetSessionRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings listSessionsTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(listSessionsMethodDescriptor) + .build(); + GrpcCallSettings deleteSessionTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(deleteSessionMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(DeleteSessionRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings reportSessionTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(reportSessionMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(ReportSessionRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings listTestsTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(listTestsMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(ListTestsRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("parent", String.valueOf(request.getParent())); + return params.build(); + } + }) + .build(); + GrpcCallSettings deleteTestTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(deleteTestMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(DeleteTestRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings verifyTestTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(verifyTestMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(VerifyTestRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + + this.createSessionCallable = + callableFactory.createUnaryCallable( + createSessionTransportSettings, settings.createSessionSettings(), clientContext); + this.getSessionCallable = + callableFactory.createUnaryCallable( + getSessionTransportSettings, settings.getSessionSettings(), clientContext); + this.listSessionsCallable = + callableFactory.createUnaryCallable( + listSessionsTransportSettings, settings.listSessionsSettings(), clientContext); + this.listSessionsPagedCallable = + callableFactory.createPagedCallable( + listSessionsTransportSettings, settings.listSessionsSettings(), clientContext); + this.deleteSessionCallable = + callableFactory.createUnaryCallable( + deleteSessionTransportSettings, settings.deleteSessionSettings(), clientContext); + this.reportSessionCallable = + callableFactory.createUnaryCallable( + reportSessionTransportSettings, settings.reportSessionSettings(), clientContext); + this.listTestsCallable = + callableFactory.createUnaryCallable( + listTestsTransportSettings, settings.listTestsSettings(), clientContext); + this.listTestsPagedCallable = + callableFactory.createPagedCallable( + listTestsTransportSettings, settings.listTestsSettings(), clientContext); + this.deleteTestCallable = + callableFactory.createUnaryCallable( + deleteTestTransportSettings, settings.deleteTestSettings(), clientContext); + this.verifyTestCallable = + callableFactory.createUnaryCallable( + verifyTestTransportSettings, settings.verifyTestSettings(), clientContext); + + this.backgroundResources = + new BackgroundResourceAggregation(clientContext.getBackgroundResources()); + } + + public GrpcOperationsStub getOperationsStub() { + return operationsStub; + } + + public UnaryCallable createSessionCallable() { + return createSessionCallable; + } + + public UnaryCallable getSessionCallable() { + return getSessionCallable; + } + + public UnaryCallable listSessionsCallable() { + return listSessionsCallable; + } + + public UnaryCallable listSessionsPagedCallable() { + return listSessionsPagedCallable; + } + + public UnaryCallable deleteSessionCallable() { + return deleteSessionCallable; + } + + public UnaryCallable reportSessionCallable() { + return reportSessionCallable; + } + + public UnaryCallable listTestsCallable() { + return listTestsCallable; + } + + public UnaryCallable listTestsPagedCallable() { + return listTestsPagedCallable; + } + + public UnaryCallable deleteTestCallable() { + return deleteTestCallable; + } + + public UnaryCallable verifyTestCallable() { + return verifyTestCallable; + } + + @Override + public final void close() { + shutdown(); + } + + @Override + public void shutdown() { + backgroundResources.shutdown(); + } + + @Override + public boolean isShutdown() { + return backgroundResources.isShutdown(); + } + + @Override + public boolean isTerminated() { + return backgroundResources.isTerminated(); + } + + @Override + public void shutdownNow() { + backgroundResources.shutdownNow(); + } + + @Override + public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException { + return backgroundResources.awaitTermination(duration, unit); + } +} diff --git a/test/integration/BUILD.bazel b/test/integration/BUILD.bazel index 11f96c0dbe..a6f574438f 100644 --- a/test/integration/BUILD.bazel +++ b/test/integration/BUILD.bazel @@ -3,7 +3,6 @@ load( "proto_library_with_info", java_gapic_library = "java_gapic_library2", ) - load( "//:rules_bazel/java/integration_test.bzl", "integration_test", @@ -58,6 +57,6 @@ java_gapic_library( integration_test( name = "redis", - target = ":redis_java_gapic", data = ["//test/integration/goldens/redis:goldens_files"], + target = ":redis_java_gapic", ) From 529355182a3edb0da2d7fecf63c7095b0e2dfd1f Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 13:50:40 -0700 Subject: [PATCH 5/9] feat: add GrpcPublisherStub test to exercise HTTP subfields --- .../GrpcServiceStubClassComposerTest.java | 32 ++ .../composer/goldens/GrpcPublisherStub.golden | 438 ++++++++++++++++++ 2 files changed, 470 insertions(+) create mode 100644 src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcPublisherStub.golden diff --git a/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java index 402d94450a..28f7bec18f 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/GrpcServiceStubClassComposerTest.java @@ -26,10 +26,13 @@ import com.google.api.generator.test.framework.Utils; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; +import com.google.pubsub.v1.PubsubProto; import com.google.showcase.v1beta1.EchoOuterClass; import com.google.showcase.v1beta1.TestingOuterClass; +import google.cloud.CommonResources; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -82,4 +85,33 @@ public void generateGrpcServiceStubClass_httpBindings() { Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "GrpcTestingStub.golden"); Assert.assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + public void generateGrpcServiceStubClass_httpBindingsWithSubMessageFields() { + FileDescriptor serviceFileDescriptor = PubsubProto.getDescriptor(); + FileDescriptor commonResourcesFileDescriptor = CommonResources.getDescriptor(); + ServiceDescriptor serviceDescriptor = serviceFileDescriptor.getServices().get(0); + assertEquals("Publisher", serviceDescriptor.getName()); + + Map resourceNames = new HashMap<>(); + resourceNames.putAll(Parser.parseResourceNames(serviceFileDescriptor)); + resourceNames.putAll(Parser.parseResourceNames(commonResourcesFileDescriptor)); + + Map messageTypes = Parser.parseMessages(serviceFileDescriptor); + + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService( + serviceFileDescriptor, messageTypes, resourceNames, outputResourceNames); + + Service service = services.get(0); + GapicClass clazz = GrpcServiceStubClassComposer.instance().generate(service, messageTypes); + + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + Utils.saveCodegenToFile(this.getClass(), "GrpcPublisherStub.golden", visitor.write()); + Path goldenFilePath = + Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "GrpcPublisherStub.golden"); + Assert.assertCodeEquals(goldenFilePath, visitor.write()); + } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcPublisherStub.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcPublisherStub.golden new file mode 100644 index 0000000000..719c3d3e03 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/GrpcPublisherStub.golden @@ -0,0 +1,438 @@ +package com.google.pubsub.v1.stub; + +import static com.google.pubsub.v1.PublisherClient.ListTopicSnapshotsPagedResponse; +import static com.google.pubsub.v1.PublisherClient.ListTopicSubscriptionsPagedResponse; +import static com.google.pubsub.v1.PublisherClient.ListTopicsPagedResponse; + +import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.core.BackgroundResourceAggregation; +import com.google.api.gax.grpc.GrpcCallSettings; +import com.google.api.gax.grpc.GrpcStubCallableFactory; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.RequestParamsExtractor; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.common.collect.ImmutableMap; +import com.google.longrunning.stub.GrpcOperationsStub; +import com.google.protobuf.Empty; +import com.google.pubsub.v1.DeleteTopicRequest; +import com.google.pubsub.v1.DetachSubscriptionRequest; +import com.google.pubsub.v1.DetachSubscriptionResponse; +import com.google.pubsub.v1.GetTopicRequest; +import com.google.pubsub.v1.ListTopicSnapshotsRequest; +import com.google.pubsub.v1.ListTopicSnapshotsResponse; +import com.google.pubsub.v1.ListTopicSubscriptionsRequest; +import com.google.pubsub.v1.ListTopicSubscriptionsResponse; +import com.google.pubsub.v1.ListTopicsRequest; +import com.google.pubsub.v1.ListTopicsResponse; +import com.google.pubsub.v1.PublishRequest; +import com.google.pubsub.v1.PublishResponse; +import com.google.pubsub.v1.Topic; +import com.google.pubsub.v1.UpdateTopicRequest; +import io.grpc.MethodDescriptor; +import io.grpc.protobuf.ProtoUtils; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * gRPC stub implementation for the Publisher service API. + * + *

This class is for advanced usage and reflects the underlying API directly. + */ +@Generated("by gapic-generator-java") +public class GrpcPublisherStub extends PublisherStub { + private static final MethodDescriptor createTopicMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/CreateTopic") + .setRequestMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance())) + .build(); + + private static final MethodDescriptor updateTopicMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/UpdateTopic") + .setRequestMarshaller(ProtoUtils.marshaller(UpdateTopicRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance())) + .build(); + + private static final MethodDescriptor publishMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/Publish") + .setRequestMarshaller(ProtoUtils.marshaller(PublishRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(PublishResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor getTopicMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/GetTopic") + .setRequestMarshaller(ProtoUtils.marshaller(GetTopicRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + listTopicsMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/ListTopics") + .setRequestMarshaller(ProtoUtils.marshaller(ListTopicsRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(ListTopicsResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor< + ListTopicSubscriptionsRequest, ListTopicSubscriptionsResponse> + listTopicSubscriptionsMethodDescriptor = + MethodDescriptor + .newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/ListTopicSubscriptions") + .setRequestMarshaller( + ProtoUtils.marshaller(ListTopicSubscriptionsRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(ListTopicSubscriptionsResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + listTopicSnapshotsMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/ListTopicSnapshots") + .setRequestMarshaller( + ProtoUtils.marshaller(ListTopicSnapshotsRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(ListTopicSnapshotsResponse.getDefaultInstance())) + .build(); + + private static final MethodDescriptor deleteTopicMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/DeleteTopic") + .setRequestMarshaller(ProtoUtils.marshaller(DeleteTopicRequest.getDefaultInstance())) + .setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance())) + .build(); + + private static final MethodDescriptor + detachSubscriptionMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.pubsub.v1.Publisher/DetachSubscription") + .setRequestMarshaller( + ProtoUtils.marshaller(DetachSubscriptionRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(DetachSubscriptionResponse.getDefaultInstance())) + .build(); + + private final UnaryCallable createTopicCallable; + private final UnaryCallable updateTopicCallable; + private final UnaryCallable publishCallable; + private final UnaryCallable getTopicCallable; + private final UnaryCallable listTopicsCallable; + private final UnaryCallable listTopicsPagedCallable; + private final UnaryCallable + listTopicSubscriptionsCallable; + private final UnaryCallable + listTopicSubscriptionsPagedCallable; + private final UnaryCallable + listTopicSnapshotsCallable; + private final UnaryCallable + listTopicSnapshotsPagedCallable; + private final UnaryCallable deleteTopicCallable; + private final UnaryCallable + detachSubscriptionCallable; + + private final BackgroundResource backgroundResources; + private final GrpcOperationsStub operationsStub; + private final GrpcStubCallableFactory callableFactory; + + public static final GrpcPublisherStub create(PublisherStubSettings settings) throws IOException { + return new GrpcPublisherStub(settings, ClientContext.create(settings)); + } + + public static final GrpcPublisherStub create(ClientContext clientContext) throws IOException { + return new GrpcPublisherStub(PublisherStubSettings.newBuilder().build(), clientContext); + } + + public static final GrpcPublisherStub create( + ClientContext clientContext, GrpcStubCallableFactory callableFactory) throws IOException { + return new GrpcPublisherStub( + PublisherStubSettings.newBuilder().build(), clientContext, callableFactory); + } + + protected GrpcPublisherStub(PublisherStubSettings settings, ClientContext clientContext) + throws IOException { + this(settings, clientContext, new GrpcPublisherCallableFactory()); + } + + protected GrpcPublisherStub( + PublisherStubSettings settings, + ClientContext clientContext, + GrpcStubCallableFactory callableFactory) + throws IOException { + this.callableFactory = callableFactory; + this.operationsStub = GrpcOperationsStub.create(clientContext, callableFactory); + + GrpcCallSettings createTopicTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(createTopicMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(Topic request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("name", String.valueOf(request.getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings updateTopicTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(updateTopicMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(UpdateTopicRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic.name", String.valueOf(request.getTopic().getName())); + return params.build(); + } + }) + .build(); + GrpcCallSettings publishTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(publishMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(PublishRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic", String.valueOf(request.getTopic())); + return params.build(); + } + }) + .build(); + GrpcCallSettings getTopicTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(getTopicMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(GetTopicRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic", String.valueOf(request.getTopic())); + return params.build(); + } + }) + .build(); + GrpcCallSettings listTopicsTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(listTopicsMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(ListTopicsRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("project", String.valueOf(request.getProject())); + return params.build(); + } + }) + .build(); + GrpcCallSettings + listTopicSubscriptionsTransportSettings = + GrpcCallSettings + .newBuilder() + .setMethodDescriptor(listTopicSubscriptionsMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(ListTopicSubscriptionsRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic", String.valueOf(request.getTopic())); + return params.build(); + } + }) + .build(); + GrpcCallSettings + listTopicSnapshotsTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(listTopicSnapshotsMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(ListTopicSnapshotsRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic", String.valueOf(request.getTopic())); + return params.build(); + } + }) + .build(); + GrpcCallSettings deleteTopicTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(deleteTopicMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(DeleteTopicRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("topic", String.valueOf(request.getTopic())); + return params.build(); + } + }) + .build(); + GrpcCallSettings + detachSubscriptionTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(detachSubscriptionMethodDescriptor) + .setParamsExtractor( + new RequestParamsExtractor() { + @Override + public Map extract(DetachSubscriptionRequest request) { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("subscription", String.valueOf(request.getSubscription())); + return params.build(); + } + }) + .build(); + + this.createTopicCallable = + callableFactory.createUnaryCallable( + createTopicTransportSettings, settings.createTopicSettings(), clientContext); + this.updateTopicCallable = + callableFactory.createUnaryCallable( + updateTopicTransportSettings, settings.updateTopicSettings(), clientContext); + this.publishCallable = + callableFactory.createUnaryCallable( + publishTransportSettings, settings.publishSettings(), clientContext); + this.getTopicCallable = + callableFactory.createUnaryCallable( + getTopicTransportSettings, settings.getTopicSettings(), clientContext); + this.listTopicsCallable = + callableFactory.createUnaryCallable( + listTopicsTransportSettings, settings.listTopicsSettings(), clientContext); + this.listTopicsPagedCallable = + callableFactory.createPagedCallable( + listTopicsTransportSettings, settings.listTopicsSettings(), clientContext); + this.listTopicSubscriptionsCallable = + callableFactory.createUnaryCallable( + listTopicSubscriptionsTransportSettings, + settings.listTopicSubscriptionsSettings(), + clientContext); + this.listTopicSubscriptionsPagedCallable = + callableFactory.createPagedCallable( + listTopicSubscriptionsTransportSettings, + settings.listTopicSubscriptionsSettings(), + clientContext); + this.listTopicSnapshotsCallable = + callableFactory.createUnaryCallable( + listTopicSnapshotsTransportSettings, + settings.listTopicSnapshotsSettings(), + clientContext); + this.listTopicSnapshotsPagedCallable = + callableFactory.createPagedCallable( + listTopicSnapshotsTransportSettings, + settings.listTopicSnapshotsSettings(), + clientContext); + this.deleteTopicCallable = + callableFactory.createUnaryCallable( + deleteTopicTransportSettings, settings.deleteTopicSettings(), clientContext); + this.detachSubscriptionCallable = + callableFactory.createUnaryCallable( + detachSubscriptionTransportSettings, + settings.detachSubscriptionSettings(), + clientContext); + + this.backgroundResources = + new BackgroundResourceAggregation(clientContext.getBackgroundResources()); + } + + public GrpcOperationsStub getOperationsStub() { + return operationsStub; + } + + public UnaryCallable createTopicCallable() { + return createTopicCallable; + } + + public UnaryCallable updateTopicCallable() { + return updateTopicCallable; + } + + public UnaryCallable publishCallable() { + return publishCallable; + } + + public UnaryCallable getTopicCallable() { + return getTopicCallable; + } + + public UnaryCallable listTopicsCallable() { + return listTopicsCallable; + } + + public UnaryCallable listTopicsPagedCallable() { + return listTopicsPagedCallable; + } + + public UnaryCallable + listTopicSubscriptionsCallable() { + return listTopicSubscriptionsCallable; + } + + public UnaryCallable + listTopicSubscriptionsPagedCallable() { + return listTopicSubscriptionsPagedCallable; + } + + public UnaryCallable + listTopicSnapshotsCallable() { + return listTopicSnapshotsCallable; + } + + public UnaryCallable + listTopicSnapshotsPagedCallable() { + return listTopicSnapshotsPagedCallable; + } + + public UnaryCallable deleteTopicCallable() { + return deleteTopicCallable; + } + + public UnaryCallable + detachSubscriptionCallable() { + return detachSubscriptionCallable; + } + + @Override + public final void close() { + shutdown(); + } + + @Override + public void shutdown() { + backgroundResources.shutdown(); + } + + @Override + public boolean isShutdown() { + return backgroundResources.isShutdown(); + } + + @Override + public boolean isTerminated() { + return backgroundResources.isTerminated(); + } + + @Override + public void shutdownNow() { + backgroundResources.shutdownNow(); + } + + @Override + public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException { + return backgroundResources.awaitTermination(duration, unit); + } +} From 2a50453099484eb68ed0040399cadf495dced77c Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 14:02:09 -0700 Subject: [PATCH 6/9] fix: add ByteString to DefaultValueComposer --- .../gapic/composer/DefaultValueComposer.java | 11 +++++++++++ .../gapic/composer/DefaultValueComposerTest.java | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java index 2994fef37b..161d7d725e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java @@ -22,6 +22,7 @@ import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.model.Field; import com.google.api.generator.gapic.model.Message; @@ -32,6 +33,7 @@ import com.google.common.base.Preconditions; import com.google.longrunning.Operation; import com.google.protobuf.Any; +import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -44,6 +46,8 @@ public class DefaultValueComposer { private static TypeNode OPERATION_TYPE = TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); private static TypeNode ANY_TYPE = TypeNode.withReference(ConcreteReference.withClazz(Any.class)); + private static TypeNode BYTESTRING_TYPE = + TypeNode.withReference(ConcreteReference.withClazz(ByteString.class)); static Expr createDefaultValue( MethodArgument methodArg, Map resourceNames) { @@ -122,6 +126,13 @@ static Expr createDefaultValue(Field f) { PrimitiveValue.builder().setType(f.type()).setValue("true").build()); } + if (f.type().equals(BYTESTRING_TYPE)) { + return VariableExpr.builder() + .setStaticReferenceType(BYTESTRING_TYPE) + .setVariable(Variable.builder().setName("EMPTY").setType(BYTESTRING_TYPE).build()) + .build(); + } + throw new UnsupportedOperationException( String.format( "Default value for field %s with type %s not implemented yet.", f.name(), f.type())); diff --git a/src/test/java/com/google/api/generator/gapic/composer/DefaultValueComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/DefaultValueComposerTest.java index 65371700bc..43f2507dad 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/DefaultValueComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/DefaultValueComposerTest.java @@ -17,6 +17,7 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import com.google.api.generator.engine.ast.ConcreteReference; import com.google.api.generator.engine.ast.Expr; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.writer.JavaWriterVisitor; @@ -24,6 +25,7 @@ import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.protoparser.Parser; +import com.google.protobuf.ByteString; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.showcase.v1beta1.EchoOuterClass; import com.google.testgapic.v1beta1.LockerProto; @@ -129,6 +131,18 @@ public void defaultValue_booleanField() { assertEquals("true", writerVisitor.write()); } + @Test + public void defaultValue_byteStringField() { + Field field = + Field.builder() + .setName("foobar") + .setType(TypeNode.withReference(ConcreteReference.withClazz(ByteString.class))) + .build(); + Expr expr = DefaultValueComposer.createDefaultValue(field); + expr.accept(writerVisitor); + assertEquals("ByteString.EMPTY", writerVisitor.write()); + } + @Test public void defaultValue_resourceNameWithOnePattern() { FileDescriptor lockerServiceFileDescriptor = LockerProto.getDescriptor(); From e4684f38fcf770aebbc0b0dc0d1507dce078321d Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 14:19:32 -0700 Subject: [PATCH 7/9] fix: Use repeated field name for paged RPC unit tests --- .../gapic/composer/DefaultValueComposer.java | 5 +++-- .../composer/ServiceClientTestClassComposer.java | 10 +++++++++- test/integration/BUILD.bazel | 16 ++++++++++------ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java index 161d7d725e..fe4064ecee 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/DefaultValueComposer.java @@ -294,7 +294,8 @@ static Expr createSimpleOperationBuilderExpr(String name, VariableExpr responseE .build(); } - static Expr createSimplePagedResponse(TypeNode responseType, Expr responseElementVarExpr) { + static Expr createSimplePagedResponse( + TypeNode responseType, String repeatedFieldName, Expr responseElementVarExpr) { Expr pagedResponseExpr = MethodInvocationExpr.builder() .setStaticReferenceType(responseType) @@ -309,7 +310,7 @@ static Expr createSimplePagedResponse(TypeNode responseType, Expr responseElemen pagedResponseExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(pagedResponseExpr) - .setMethodName("addAllResponses") + .setMethodName(String.format("addAll%s", JavaStyle.toUpperCamelCase(repeatedFieldName))) .setArguments( MethodInvocationExpr.builder() .setStaticReferenceType( diff --git a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java index 77e291e01b..e606f0c768 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java @@ -514,9 +514,17 @@ private static MethodDefinition createRpcTestMethod( Variable.builder().setType(methodOutputType).setName("expectedResponse").build()); Expr expectedResponseValExpr = null; if (method.isPaged()) { + Message methodOutputMessage = messageTypes.get(method.outputType().reference().name()); + Field firstRepeatedField = methodOutputMessage.findAndUnwrapFirstRepeatedField(); + Preconditions.checkNotNull( + firstRepeatedField, + String.format( + "Expected paged RPC %s to have a repeated field in the response %s but found none", + method.name(), methodOutputMessage.name())); + expectedResponseValExpr = DefaultValueComposer.createSimplePagedResponse( - method.outputType(), responsesElementVarExpr); + method.outputType(), firstRepeatedField.name(), responsesElementVarExpr); } else { if (messageTypes.containsKey(methodOutputType.reference().name())) { expectedResponseValExpr = diff --git a/test/integration/BUILD.bazel b/test/integration/BUILD.bazel index a6f574438f..868b623005 100644 --- a/test/integration/BUILD.bazel +++ b/test/integration/BUILD.bazel @@ -10,6 +10,16 @@ load( package(default_visibility = ["//visibility:public"]) +#################################################### +# Integration Test Rules +#################################################### + +integration_test( + name = "redis", + data = ["//test/integration/goldens/redis:goldens_files"], + target = ":redis_java_gapic", +) + #################################################### # API Library Rules #################################################### @@ -54,9 +64,3 @@ java_gapic_library( "@com_google_googleapis//google/cloud/redis/v1:redis_java_proto", ], ) - -integration_test( - name = "redis", - data = ["//test/integration/goldens/redis:goldens_files"], - target = ":redis_java_gapic", -) From c304cc10369a8fbbd4da06ea394de4eb08ea73a1 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Thu, 22 Oct 2020 12:06:39 -0700 Subject: [PATCH 8/9] fix: change getter too --- .../ServiceClientTestClassComposer.java | 42 +++++++++++++++---- .../composer/goldens/EchoClientTest.golden | 4 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java index e606f0c768..c1f5fdbbbf 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java @@ -103,11 +103,11 @@ public class ServiceClientTestClassComposer { private static final String GRPC_TESTING_PACKAGE = "com.google.api.gax.grpc.testing"; private static final String MOCK_SERVICE_CLASS_NAME_PATTERN = "Mock%s"; private static final String MOCK_SERVICE_VAR_NAME_PATTERN = "mock%s"; + private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse"; private static final String SERVICE_CLIENT_CLASS_NAME_PATTERN = "%sClient"; private static final String SERVICE_HELPER_VAR_NAME = "mockServiceHelper"; private static final String SERVICE_SETTINGS_CLASS_NAME_PATTERN = "%sSettings"; private static final String STUB_SETTINGS_PATTERN = "%sSettings"; - private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse"; private static final ServiceClientTestClassComposer INSTANCE = new ServiceClientTestClassComposer(); @@ -424,18 +424,18 @@ private static List createTestMethods( javaMethods.add( createRpcTestMethod( method, + service, Collections.emptyList(), 0, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); javaMethods.add( createRpcExceptionTestMethod( method, + service, Collections.emptyList(), 0, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); @@ -444,18 +444,18 @@ private static List createTestMethods( javaMethods.add( createRpcTestMethod( method, + service, method.methodSignatures().get(i), i, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); javaMethods.add( createRpcExceptionTestMethod( method, + service, method.methodSignatures().get(i), i, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); @@ -467,12 +467,14 @@ private static List createTestMethods( private static MethodDefinition createRpcTestMethod( Method method, + Service service, List methodSignature, int variantIndex, - String serviceName, Map classMemberVarExprs, Map resourceNames, Map messageTypes) { + String serviceName = service.name(); + if (!method.stream().equals(Method.Stream.NONE)) { return createStreamingRpcTestMethod( method, serviceName, classMemberVarExprs, resourceNames, messageTypes); @@ -627,7 +629,8 @@ private static MethodDefinition createRpcTestMethod( VariableExpr actualResponseVarExpr = VariableExpr.withVariable( Variable.builder() - .setType(methodOutputType) + .setType( + method.isPaged() ? getPagedResponseType(service, method) : methodOutputType) .setName(method.isPaged() ? "pagedListResponse" : "actualResponse") .build()); Expr rpcJavaMethodInvocationExpr = @@ -707,12 +710,21 @@ private static MethodDefinition createRpcTestMethod( .build()); // Assert the responses are equivalent. + Message methodOutputMessage = messageTypes.get(method.outputType().reference().name()); + Field firstRepeatedField = methodOutputMessage.findAndUnwrapFirstRepeatedField(); + Preconditions.checkNotNull( + firstRepeatedField, + String.format( + "Expected paged RPC %s to have a repeated field in the response %s but found none", + method.name(), methodOutputMessage.name())); + Expr zeroExpr = ValueExpr.withValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("0").build()); Expr expectedPagedResponseExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(expectedResponseVarExpr) - .setMethodName("getResponsesList") + .setMethodName( + String.format("get%sList", JavaStyle.toUpperCamelCase(firstRepeatedField.name()))) .build(); expectedPagedResponseExpr = MethodInvocationExpr.builder() @@ -1168,12 +1180,14 @@ private static MethodDefinition createStreamingRpcTestMethod( private static MethodDefinition createRpcExceptionTestMethod( Method method, + Service service, List methodSignature, int variantIndex, - String serviceName, Map classMemberVarExprs, Map resourceNames, Map messageTypes) { + String serviceName = service.name(); + VariableExpr exceptionVarExpr = VariableExpr.withVariable( Variable.builder() @@ -1841,6 +1855,16 @@ private static TypeNode getCallableType(Method protoMethod) { ConcreteReference.builder().setClazz(callableClazz).setGenerics(generics).build()); } + private static TypeNode getPagedResponseType(Service service, Method method) { + return TypeNode.withReference( + VaporReference.builder() + .setName(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name())) + .setPakkage(service.pakkage()) + .setEnclosingClassName(getClientClassName(service.name())) + .setIsStaticImport(true) + .build()); + } + private static String getCallableMethodName(Method protoMethod) { Preconditions.checkState( !protoMethod.stream().equals(Method.Stream.NONE), diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden index edaebc54b0..aa4004bda4 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden @@ -1,5 +1,7 @@ package com.google.showcase.v1beta1; +import static com.google.showcase.v1beta1.EchoClient.PagedExpandPagedResponse; + import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GaxGrpcProperties; import com.google.api.gax.grpc.testing.LocalChannelProvider; @@ -550,7 +552,7 @@ public class EchoClientTest { .setPageToken("page_token1630607433") .build(); - PagedExpandResponse pagedListResponse = client.pagedExpand(request); + PagedExpandPagedResponse pagedListResponse = client.pagedExpand(request); List resources = Lists.newArrayList(pagedListResponse.iterateAll()); From 7829850915248e128366f0ae9df4579f36507ef6 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Thu, 22 Oct 2020 14:30:20 -0700 Subject: [PATCH 9/9] fix: refactor exception field, use paged repeated field name, add pubsub client test --- .../ServiceClientTestClassComposer.java | 41 +- .../ServiceClientTestClassComposerTest.java | 50 +- .../composer/goldens/EchoClientTest.golden | 4 +- .../goldens/SubscriberClientTest.golden | 1503 +++++++++++++++++ 4 files changed, 1578 insertions(+), 20 deletions(-) create mode 100644 src/test/java/com/google/api/generator/gapic/composer/goldens/SubscriberClientTest.golden diff --git a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java index e606f0c768..98bfc42b6e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposer.java @@ -424,18 +424,18 @@ private static List createTestMethods( javaMethods.add( createRpcTestMethod( method, + service, Collections.emptyList(), 0, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); javaMethods.add( createRpcExceptionTestMethod( method, + service, Collections.emptyList(), 0, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); @@ -444,18 +444,18 @@ private static List createTestMethods( javaMethods.add( createRpcTestMethod( method, + service, method.methodSignatures().get(i), i, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); javaMethods.add( createRpcExceptionTestMethod( method, + service, method.methodSignatures().get(i), i, - service.name(), classMemberVarExprs, resourceNames, messageTypes)); @@ -467,12 +467,14 @@ private static List createTestMethods( private static MethodDefinition createRpcTestMethod( Method method, + Service service, List methodSignature, int variantIndex, - String serviceName, Map classMemberVarExprs, Map resourceNames, Map messageTypes) { + String serviceName = service.name(); + if (!method.stream().equals(Method.Stream.NONE)) { return createStreamingRpcTestMethod( method, serviceName, classMemberVarExprs, resourceNames, messageTypes); @@ -627,7 +629,8 @@ private static MethodDefinition createRpcTestMethod( VariableExpr actualResponseVarExpr = VariableExpr.withVariable( Variable.builder() - .setType(methodOutputType) + .setType( + method.isPaged() ? getPagedResponseType(method, service) : methodOutputType) .setName(method.isPaged() ? "pagedListResponse" : "actualResponse") .build()); Expr rpcJavaMethodInvocationExpr = @@ -707,12 +710,22 @@ private static MethodDefinition createRpcTestMethod( .build()); // Assert the responses are equivalent. + Message methodOutputMessage = messageTypes.get(method.outputType().reference().name()); + Field repeatedPagedResultsField = methodOutputMessage.findAndUnwrapFirstRepeatedField(); + Preconditions.checkNotNull( + repeatedPagedResultsField, + String.format( + "No repeated field found for paged method %s with output message type %s", + method.name(), methodOutputMessage.name())); + Expr zeroExpr = ValueExpr.withValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("0").build()); Expr expectedPagedResponseExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(expectedResponseVarExpr) - .setMethodName("getResponsesList") + .setMethodName( + String.format( + "get%sList", JavaStyle.toUpperCamelCase(repeatedPagedResultsField.name()))) .build(); expectedPagedResponseExpr = MethodInvocationExpr.builder() @@ -1168,12 +1181,14 @@ private static MethodDefinition createStreamingRpcTestMethod( private static MethodDefinition createRpcExceptionTestMethod( Method method, + Service service, List methodSignature, int variantIndex, - String serviceName, Map classMemberVarExprs, Map resourceNames, Map messageTypes) { + String serviceName = service.name(); + VariableExpr exceptionVarExpr = VariableExpr.withVariable( Variable.builder() @@ -1841,6 +1856,16 @@ private static TypeNode getCallableType(Method protoMethod) { ConcreteReference.builder().setClazz(callableClazz).setGenerics(generics).build()); } + private static TypeNode getPagedResponseType(Method method, Service service) { + return TypeNode.withReference( + VaporReference.builder() + .setName(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name())) + .setPakkage(service.pakkage()) + .setEnclosingClassName(getClientClassName(service.name())) + .setIsStaticImport(true) + .build()); + } + private static String getCallableMethodName(Method protoMethod) { Preconditions.checkState( !protoMethod.stream().equals(Method.Stream.NONE), diff --git a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposerTest.java index 29902de51d..2fbc61a2df 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientTestClassComposerTest.java @@ -26,29 +26,25 @@ import com.google.api.generator.test.framework.Utils; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; +import com.google.pubsub.v1.PubsubProto; import com.google.showcase.v1beta1.EchoOuterClass; +import google.cloud.CommonResources; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.Before; import org.junit.Test; public class ServiceClientTestClassComposerTest { - private ServiceDescriptor echoService; - private FileDescriptor echoFileDescriptor; - - @Before - public void setUp() { - echoFileDescriptor = EchoOuterClass.getDescriptor(); - echoService = echoFileDescriptor.getServices().get(0); + @Test + public void generateClientTest_echoClient() { + FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); + ServiceDescriptor echoService = echoFileDescriptor.getServices().get(0); assertEquals(echoService.getName(), "Echo"); - } - @Test - public void generateServiceClasses() { Map messageTypes = Parser.parseMessages(echoFileDescriptor); Map resourceNames = Parser.parseResourceNames(echoFileDescriptor); Set outputResourceNames = new HashSet<>(); @@ -67,4 +63,36 @@ public void generateServiceClasses() { Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "EchoClientTest.golden"); assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + public void generateClientTest_pubSubPublisherClient() { + FileDescriptor serviceFileDescriptor = PubsubProto.getDescriptor(); + FileDescriptor commonResourcesFileDescriptor = CommonResources.getDescriptor(); + ServiceDescriptor serviceDescriptor = serviceFileDescriptor.getServices().get(0); + assertEquals("Publisher", serviceDescriptor.getName()); + + Map resourceNames = new HashMap<>(); + resourceNames.putAll(Parser.parseResourceNames(serviceFileDescriptor)); + resourceNames.putAll(Parser.parseResourceNames(commonResourcesFileDescriptor)); + + Map messageTypes = Parser.parseMessages(serviceFileDescriptor); + + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService( + serviceFileDescriptor, messageTypes, resourceNames, outputResourceNames); + + Service subscriptionService = services.get(1); + assertEquals("Subscriber", subscriptionService.name()); + GapicClass clazz = + ServiceClientTestClassComposer.instance() + .generate(subscriptionService, resourceNames, messageTypes); + + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + Utils.saveCodegenToFile(this.getClass(), "SubscriberClientTest.golden", visitor.write()); + Path goldenFilePath = + Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "SubscriberClientTest.golden"); + assertCodeEquals(goldenFilePath, visitor.write()); + } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden index edaebc54b0..aa4004bda4 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClientTest.golden @@ -1,5 +1,7 @@ package com.google.showcase.v1beta1; +import static com.google.showcase.v1beta1.EchoClient.PagedExpandPagedResponse; + import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.grpc.GaxGrpcProperties; import com.google.api.gax.grpc.testing.LocalChannelProvider; @@ -550,7 +552,7 @@ public class EchoClientTest { .setPageToken("page_token1630607433") .build(); - PagedExpandResponse pagedListResponse = client.pagedExpand(request); + PagedExpandPagedResponse pagedListResponse = client.pagedExpand(request); List resources = Lists.newArrayList(pagedListResponse.iterateAll()); diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/SubscriberClientTest.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/SubscriberClientTest.golden new file mode 100644 index 0000000000..f555386ace --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/SubscriberClientTest.golden @@ -0,0 +1,1503 @@ +package com.google.pubsub.v1; + +import static com.google.pubsub.v1.SubscriberClient.ListSnapshotsPagedResponse; +import static com.google.pubsub.v1.SubscriberClient.ListSubscriptionsPagedResponse; + +import com.google.api.gax.core.NoCredentialsProvider; +import com.google.api.gax.grpc.GaxGrpcProperties; +import com.google.api.gax.grpc.testing.LocalChannelProvider; +import com.google.api.gax.grpc.testing.MockGrpcService; +import com.google.api.gax.grpc.testing.MockServiceHelper; +import com.google.api.gax.grpc.testing.MockStreamObserver; +import com.google.api.gax.rpc.ApiClientHeaderProvider; +import com.google.api.gax.rpc.ApiStreamObserver; +import com.google.api.gax.rpc.BidiStreamingCallable; +import com.google.api.gax.rpc.InvalidArgumentException; +import com.google.api.gax.rpc.StatusCode; +import com.google.common.collect.Lists; +import com.google.protobuf.AbstractMessage; +import com.google.protobuf.Empty; +import google.cloud.ProjectName; +import io.grpc.StatusRuntimeException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import javax.annotation.Generated; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +@Generated("by gapic-generator-java") +public class SubscriberClientTest { + private static MockServiceHelper mockServiceHelper; + private static MockSubscriber mockSubscriber; + private SubscriberClient client; + private LocalChannelProvider channelProvider; + + @BeforeClass + public static void startStaticServer() { + mockSubscriber = new MockSubscriber(); + mockServiceHelper = + new MockServiceHelper( + UUID.randomUUID().toString(), Arrays.asList(mockSubscriber)); + mockServiceHelper.start(); + } + + @AfterClass + public static void stopServer() { + mockServiceHelper.stop(); + } + + @Before + public void setUp() throws IOException { + mockServiceHelper.reset(); + channelProvider = mockServiceHelper.createChannelProvider(); + SubscriberSettings settings = + SubscriberSettings.newBuilder() + .setTransportChannelProvider(channelProvider) + .setCredentialsProvider(NoCredentialsProvider.create()) + .build(); + client = SubscriberClient.create(settings); + } + + @After + public void tearDown() throws Exception { + client.close(); + } + + @Test + public void createSubscriptionTest() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName name = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + TopicName topic = TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + + Subscription actualResponse = + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + Subscription actualRequest = ((Subscription) actualRequests.get(0)); + + Assert.assertEquals(name.toString(), actualRequest.getName()); + Assert.assertEquals(topic.toString(), actualRequest.getTopic()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSubscriptionExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName name = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + TopicName topic = TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSubscriptionTest2() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName name = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + String topic = "topic110546223"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + + Subscription actualResponse = + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + Subscription actualRequest = ((Subscription) actualRequests.get(0)); + + Assert.assertEquals(name.toString(), actualRequest.getName()); + Assert.assertEquals(topic, actualRequest.getTopic()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSubscriptionExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName name = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + String topic = "topic110546223"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSubscriptionTest3() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String name = "name3373707"; + TopicName topic = TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + + Subscription actualResponse = + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + Subscription actualRequest = ((Subscription) actualRequests.get(0)); + + Assert.assertEquals(name, actualRequest.getName()); + Assert.assertEquals(topic.toString(), actualRequest.getTopic()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSubscriptionExceptionTest3() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String name = "name3373707"; + TopicName topic = TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSubscriptionTest4() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String name = "name3373707"; + String topic = "topic110546223"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + + Subscription actualResponse = + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + Subscription actualRequest = ((Subscription) actualRequests.get(0)); + + Assert.assertEquals(name, actualRequest.getName()); + Assert.assertEquals(topic, actualRequest.getTopic()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSubscriptionExceptionTest4() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String name = "name3373707"; + String topic = "topic110546223"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + int ackDeadlineSeconds = 2135351438; + client.createSubscription(name, topic, pushConfig, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void getSubscriptionTest() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + + Subscription actualResponse = client.getSubscription(subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + GetSubscriptionRequest actualRequest = ((GetSubscriptionRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void getSubscriptionExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + client.getSubscription(subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void getSubscriptionTest2() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + + Subscription actualResponse = client.getSubscription(subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + GetSubscriptionRequest actualRequest = ((GetSubscriptionRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void getSubscriptionExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + client.getSubscription(subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void updateSubscriptionTest() { + Subscription expectedResponse = + Subscription.newBuilder() + .setName(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .setPushConfig(PushConfig.newBuilder().build()) + .setAckDeadlineSeconds(2135351438) + .setRetainAckedMessages(true) + .putAllLabels(new HashMap<>()) + .setEnableMessageOrdering(true) + .setExpirationPolicy(ExpirationPolicy.newBuilder().build()) + .setFilter("filter-1274492040") + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) + .setRetryPolicy(RetryPolicy.newBuilder().build()) + .setDetached(true) + .build(); + mockSubscriber.addResponse(expectedResponse); + + UpdateSubscriptionRequest request = + UpdateSubscriptionRequest.newBuilder() + .setSubscription(Subscription.newBuilder().build()) + .build(); + + Subscription actualResponse = client.updateSubscription(request); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + UpdateSubscriptionRequest actualRequest = ((UpdateSubscriptionRequest) actualRequests.get(0)); + + Assert.assertEquals(request.getSubscription(), actualRequest.getSubscription()); + Assert.assertEquals(request.getUpdateMask(), actualRequest.getUpdateMask()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void updateSubscriptionExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + UpdateSubscriptionRequest request = + UpdateSubscriptionRequest.newBuilder() + .setSubscription(Subscription.newBuilder().build()) + .build(); + client.updateSubscription(request); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void listSubscriptionsTest() { + Subscription responsesElement = Subscription.newBuilder().build(); + ListSubscriptionsResponse expectedResponse = + ListSubscriptionsResponse.newBuilder() + .setNextPageToken("") + .addAllSubscriptions(Arrays.asList(responsesElement)) + .build(); + mockSubscriber.addResponse(expectedResponse); + + ProjectName project = ProjectName.of("[PROJECT]"); + + ListSubscriptionsPagedResponse pagedListResponse = client.listSubscriptions(project); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getSubscriptionsList().get(0), resources.get(0)); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ListSubscriptionsRequest actualRequest = ((ListSubscriptionsRequest) actualRequests.get(0)); + + Assert.assertEquals(project.toString(), actualRequest.getProject()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void listSubscriptionsExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + ProjectName project = ProjectName.of("[PROJECT]"); + client.listSubscriptions(project); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void listSubscriptionsTest2() { + Subscription responsesElement = Subscription.newBuilder().build(); + ListSubscriptionsResponse expectedResponse = + ListSubscriptionsResponse.newBuilder() + .setNextPageToken("") + .addAllSubscriptions(Arrays.asList(responsesElement)) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String project = "project-309310695"; + + ListSubscriptionsPagedResponse pagedListResponse = client.listSubscriptions(project); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getSubscriptionsList().get(0), resources.get(0)); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ListSubscriptionsRequest actualRequest = ((ListSubscriptionsRequest) actualRequests.get(0)); + + Assert.assertEquals(project, actualRequest.getProject()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void listSubscriptionsExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String project = "project-309310695"; + client.listSubscriptions(project); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void deleteSubscriptionTest() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + + Empty actualResponse = client.deleteSubscription(subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + DeleteSubscriptionRequest actualRequest = ((DeleteSubscriptionRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void deleteSubscriptionExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + client.deleteSubscription(subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void deleteSubscriptionTest2() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + + Empty actualResponse = client.deleteSubscription(subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + DeleteSubscriptionRequest actualRequest = ((DeleteSubscriptionRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void deleteSubscriptionExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + client.deleteSubscription(subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void modifyAckDeadlineTest() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + List ackIds = new ArrayList<>(); + int ackDeadlineSeconds = 2135351438; + + Empty actualResponse = client.modifyAckDeadline(subscription, ackIds, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ModifyAckDeadlineRequest actualRequest = ((ModifyAckDeadlineRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertEquals(ackIds, actualRequest.getAckIdsList()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void modifyAckDeadlineExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + List ackIds = new ArrayList<>(); + int ackDeadlineSeconds = 2135351438; + client.modifyAckDeadline(subscription, ackIds, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void modifyAckDeadlineTest2() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + List ackIds = new ArrayList<>(); + int ackDeadlineSeconds = 2135351438; + + Empty actualResponse = client.modifyAckDeadline(subscription, ackIds, ackDeadlineSeconds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ModifyAckDeadlineRequest actualRequest = ((ModifyAckDeadlineRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertEquals(ackIds, actualRequest.getAckIdsList()); + Assert.assertEquals(ackDeadlineSeconds, actualRequest.getAckDeadlineSeconds()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void modifyAckDeadlineExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + List ackIds = new ArrayList<>(); + int ackDeadlineSeconds = 2135351438; + client.modifyAckDeadline(subscription, ackIds, ackDeadlineSeconds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void acknowledgeTest() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + List ackIds = new ArrayList<>(); + + Empty actualResponse = client.acknowledge(subscription, ackIds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + AcknowledgeRequest actualRequest = ((AcknowledgeRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertEquals(ackIds, actualRequest.getAckIdsList()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void acknowledgeExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + List ackIds = new ArrayList<>(); + client.acknowledge(subscription, ackIds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void acknowledgeTest2() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + List ackIds = new ArrayList<>(); + + Empty actualResponse = client.acknowledge(subscription, ackIds); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + AcknowledgeRequest actualRequest = ((AcknowledgeRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertEquals(ackIds, actualRequest.getAckIdsList()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void acknowledgeExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + List ackIds = new ArrayList<>(); + client.acknowledge(subscription, ackIds); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void pullTest() { + PullResponse expectedResponse = + PullResponse.newBuilder().addAllReceivedMessages(new ArrayList<>()).build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + boolean returnImmediately = true; + int maxMessages = 496131527; + + PullResponse actualResponse = client.pull(subscription, returnImmediately, maxMessages); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + PullRequest actualRequest = ((PullRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertEquals(returnImmediately, actualRequest.getReturnImmediately()); + Assert.assertEquals(maxMessages, actualRequest.getMaxMessages()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void pullExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + boolean returnImmediately = true; + int maxMessages = 496131527; + client.pull(subscription, returnImmediately, maxMessages); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void pullTest2() { + PullResponse expectedResponse = + PullResponse.newBuilder().addAllReceivedMessages(new ArrayList<>()).build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + boolean returnImmediately = true; + int maxMessages = 496131527; + + PullResponse actualResponse = client.pull(subscription, returnImmediately, maxMessages); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + PullRequest actualRequest = ((PullRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertEquals(returnImmediately, actualRequest.getReturnImmediately()); + Assert.assertEquals(maxMessages, actualRequest.getMaxMessages()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void pullExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + boolean returnImmediately = true; + int maxMessages = 496131527; + client.pull(subscription, returnImmediately, maxMessages); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void streamingPullTest() { + StreamingPullResponse expectedResponse = + StreamingPullResponse.newBuilder().addAllReceivedMessages(new ArrayList<>()).build(); + mockSubscriber.addResponse(expectedResponse); + StreamingPullRequest request = + StreamingPullRequest.newBuilder() + .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .addAllAckIds(new ArrayList<>()) + .addAllModifyDeadlineSeconds(new ArrayList<>()) + .addAllModifyDeadlineAckIds(new ArrayList<>()) + .setStreamAckDeadlineSeconds(1875467245) + .setClientId("client_id-1904089585") + .setMaxOutstandingMessages(-1315266996) + .setMaxOutstandingBytes(-2103098517) + .build(); + + MockStreamObserver responseObserver = new MockStreamObserver<>(); + + BidiStreamingCallable callable = + client.streamingPullCallable(); + ApiStreamObserver requestObserver = + callable.bidiStreamingCall(request, responseObserver); + + requestObserver.onNext(request); + requestObserver.onCompleted(); + + List actualResponses = responseObserver.future().get(); + Assert.assertEquals(1, actualResponses.size()); + Assert.assertEquals(expectedResponse, actualResponses.get(0)); + } + + @Test + public void streamingPullExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + StreamingPullRequest request = + StreamingPullRequest.newBuilder() + .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .addAllAckIds(new ArrayList<>()) + .addAllModifyDeadlineSeconds(new ArrayList<>()) + .addAllModifyDeadlineAckIds(new ArrayList<>()) + .setStreamAckDeadlineSeconds(1875467245) + .setClientId("client_id-1904089585") + .setMaxOutstandingMessages(-1315266996) + .setMaxOutstandingBytes(-2103098517) + .build(); + + MockStreamObserver responseObserver = new MockStreamObserver<>(); + + BidiStreamingCallable callable = + client.streamingPullCallable(); + ApiStreamObserver requestObserver = + callable.bidiStreamingCall(request, responseObserver); + + requestObserver.onNext(request); + + try { + List actualResponses = responseObserver.future().get(); + Assert.fail("No exception thrown"); + } catch (ExecutionException e) { + Assert.assertTrue(e.getCause() instanceof InvalidArgumentException); + InvalidArgumentException apiException = ((InvalidArgumentException) e.getCause()); + Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); + } + } + + @Test + public void modifyPushConfigTest() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + + Empty actualResponse = client.modifyPushConfig(subscription, pushConfig); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ModifyPushConfigRequest actualRequest = ((ModifyPushConfigRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void modifyPushConfigExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + PushConfig pushConfig = PushConfig.newBuilder().build(); + client.modifyPushConfig(subscription, pushConfig); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void modifyPushConfigTest2() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + String subscription = "subscription341203229"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + + Empty actualResponse = client.modifyPushConfig(subscription, pushConfig); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ModifyPushConfigRequest actualRequest = ((ModifyPushConfigRequest) actualRequests.get(0)); + + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertEquals(pushConfig, actualRequest.getPushConfig()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void modifyPushConfigExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String subscription = "subscription341203229"; + PushConfig pushConfig = PushConfig.newBuilder().build(); + client.modifyPushConfig(subscription, pushConfig); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void getSnapshotTest() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SnapshotName snapshot = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + + Snapshot actualResponse = client.getSnapshot(snapshot); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + GetSnapshotRequest actualRequest = ((GetSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(snapshot.toString(), actualRequest.getSnapshot()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void getSnapshotExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SnapshotName snapshot = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + client.getSnapshot(snapshot); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void getSnapshotTest2() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String snapshot = "snapshot284874180"; + + Snapshot actualResponse = client.getSnapshot(snapshot); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + GetSnapshotRequest actualRequest = ((GetSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(snapshot, actualRequest.getSnapshot()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void getSnapshotExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String snapshot = "snapshot284874180"; + client.getSnapshot(snapshot); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void listSnapshotsTest() { + Snapshot responsesElement = Snapshot.newBuilder().build(); + ListSnapshotsResponse expectedResponse = + ListSnapshotsResponse.newBuilder() + .setNextPageToken("") + .addAllSnapshots(Arrays.asList(responsesElement)) + .build(); + mockSubscriber.addResponse(expectedResponse); + + ProjectName project = ProjectName.of("[PROJECT]"); + + ListSnapshotsPagedResponse pagedListResponse = client.listSnapshots(project); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getSnapshotsList().get(0), resources.get(0)); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ListSnapshotsRequest actualRequest = ((ListSnapshotsRequest) actualRequests.get(0)); + + Assert.assertEquals(project.toString(), actualRequest.getProject()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void listSnapshotsExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + ProjectName project = ProjectName.of("[PROJECT]"); + client.listSnapshots(project); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void listSnapshotsTest2() { + Snapshot responsesElement = Snapshot.newBuilder().build(); + ListSnapshotsResponse expectedResponse = + ListSnapshotsResponse.newBuilder() + .setNextPageToken("") + .addAllSnapshots(Arrays.asList(responsesElement)) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String project = "project-309310695"; + + ListSnapshotsPagedResponse pagedListResponse = client.listSnapshots(project); + + List resources = Lists.newArrayList(pagedListResponse.iterateAll()); + + Assert.assertEquals(1, resources.size()); + Assert.assertEquals(expectedResponse.getSnapshotsList().get(0), resources.get(0)); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + ListSnapshotsRequest actualRequest = ((ListSnapshotsRequest) actualRequests.get(0)); + + Assert.assertEquals(project, actualRequest.getProject()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void listSnapshotsExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String project = "project-309310695"; + client.listSnapshots(project); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSnapshotTest() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SnapshotName name = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + + Snapshot actualResponse = client.createSnapshot(name, subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + CreateSnapshotRequest actualRequest = ((CreateSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(name.toString(), actualRequest.getName()); + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSnapshotExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SnapshotName name = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + client.createSnapshot(name, subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSnapshotTest2() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + SnapshotName name = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + String subscription = "subscription341203229"; + + Snapshot actualResponse = client.createSnapshot(name, subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + CreateSnapshotRequest actualRequest = ((CreateSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(name.toString(), actualRequest.getName()); + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSnapshotExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SnapshotName name = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + String subscription = "subscription341203229"; + client.createSnapshot(name, subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSnapshotTest3() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String name = "name3373707"; + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + + Snapshot actualResponse = client.createSnapshot(name, subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + CreateSnapshotRequest actualRequest = ((CreateSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(name, actualRequest.getName()); + Assert.assertEquals(subscription.toString(), actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSnapshotExceptionTest3() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String name = "name3373707"; + SubscriptionName subscription = SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]"); + client.createSnapshot(name, subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void createSnapshotTest4() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + String name = "name3373707"; + String subscription = "subscription341203229"; + + Snapshot actualResponse = client.createSnapshot(name, subscription); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + CreateSnapshotRequest actualRequest = ((CreateSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(name, actualRequest.getName()); + Assert.assertEquals(subscription, actualRequest.getSubscription()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void createSnapshotExceptionTest4() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String name = "name3373707"; + String subscription = "subscription341203229"; + client.createSnapshot(name, subscription); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void updateSnapshotTest() { + Snapshot expectedResponse = + Snapshot.newBuilder() + .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString()) + .setTopic(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString()) + .putAllLabels(new HashMap<>()) + .build(); + mockSubscriber.addResponse(expectedResponse); + + UpdateSnapshotRequest request = + UpdateSnapshotRequest.newBuilder().setSnapshot(Snapshot.newBuilder().build()).build(); + + Snapshot actualResponse = client.updateSnapshot(request); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + UpdateSnapshotRequest actualRequest = ((UpdateSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(request.getSnapshot(), actualRequest.getSnapshot()); + Assert.assertEquals(request.getUpdateMask(), actualRequest.getUpdateMask()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void updateSnapshotExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + UpdateSnapshotRequest request = + UpdateSnapshotRequest.newBuilder().setSnapshot(Snapshot.newBuilder().build()).build(); + client.updateSnapshot(request); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void deleteSnapshotTest() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SnapshotName snapshot = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + + Empty actualResponse = client.deleteSnapshot(snapshot); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + DeleteSnapshotRequest actualRequest = ((DeleteSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(snapshot.toString(), actualRequest.getSnapshot()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void deleteSnapshotExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SnapshotName snapshot = SnapshotName.of("[PROJECT]", "[SNAPSHOT]"); + client.deleteSnapshot(snapshot); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void deleteSnapshotTest2() { + Empty expectedResponse = Empty.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + String snapshot = "snapshot284874180"; + + Empty actualResponse = client.deleteSnapshot(snapshot); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + DeleteSnapshotRequest actualRequest = ((DeleteSnapshotRequest) actualRequests.get(0)); + + Assert.assertEquals(snapshot, actualRequest.getSnapshot()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void deleteSnapshotExceptionTest2() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + String snapshot = "snapshot284874180"; + client.deleteSnapshot(snapshot); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } + + @Test + public void seekTest() { + SeekResponse expectedResponse = SeekResponse.newBuilder().build(); + mockSubscriber.addResponse(expectedResponse); + + SeekRequest request = + SeekRequest.newBuilder() + .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .build(); + + SeekResponse actualResponse = client.seek(request); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockSubscriber.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + SeekRequest actualRequest = ((SeekRequest) actualRequests.get(0)); + + Assert.assertEquals(request.getSubscription(), actualRequest.getSubscription()); + Assert.assertEquals(request.getTime(), actualRequest.getTime()); + Assert.assertEquals(request.getSnapshot(), actualRequest.getSnapshot()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void seekExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockSubscriber.addException(exception); + + try { + SeekRequest request = + SeekRequest.newBuilder() + .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString()) + .build(); + client.seek(request); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } +}