From 5709ffdb328237856e01fe0f49dfc94a08e9d595 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Fri, 28 Aug 2020 23:01:56 -0700 Subject: [PATCH] [ggj][codegen] fix: handle singleton resname patterns, name_field, add logging test (#250) * feat: add factory var decl in ServiceStubSettings codegen * fix: prevent duplicate MethodDefinition annotations * feat: add descriptor fields to ServiceStubSettings codegen * feat: add starter Builder to ServiceStubSettings codegen * feat: add settings.builder decls to ServiceStubSettings codegen * feat: add first nested ctors to ServiceStubSettings codegen * feat: add GapicServiceConfig DS and processing * feat: integrate GapicServiceConfig into GapicContext, Parser, Composer * feat: initial param block, RetrySettingsComposer, test * fix!: refactor GapicRetrySettings * fix: recognize 1. or .1 double patterns * feat: support BlockStatement in ClassDef stmts * feat: add params block to ServiceStubSettings codegen * feat: add codes def to ServiceStubSettings codegen * feat: add initDefaults() to ServiceStubSettings codegen * feat: add LRO to ServiceStubSettings.Builder.initDefaults * feat: add third ServiceStubSettings.Builder(settings) ctor * feat: add createDefault() to ServiceStubSettings * feat: add ServiceStubSettings.applyToAllUnaryMethods method * feat: add ServiceStubSettings.unaryMethodSettingsBuilders() * feat: add ServiceStubSettings.build() * feat: add settingsBuilder getters in ServiceStubSettings * feat: add gapic.yaml batching parsing * feat: integrate batching with retry settings parsing * fix: remove unused test proto imports * fix: handle singleton resname patterns, name_field, add logging test * fix: pass in logging grpc service config --- .../BatchingSettingsConfigParser.java | 2 + .../generator/gapic/protoparser/Parser.java | 12 +- .../gapic/protoparser/ResourceNameParser.java | 37 +- .../api/generator/gapic/composer/BUILD.bazel | 9 + .../ServiceStubSettingsClassComposerTest.java | 674 +++++++++++++++++- .../protoparser/ResourceNameParserTest.java | 16 +- .../testdata/logging_grpc_service_config.json | 162 +++++ 7 files changed, 869 insertions(+), 43 deletions(-) create mode 100644 src/test/java/com/google/api/generator/gapic/testdata/logging_grpc_service_config.json diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/BatchingSettingsConfigParser.java b/src/main/java/com/google/api/generator/gapic/protoparser/BatchingSettingsConfigParser.java index 71ac168343..721b79beea 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/BatchingSettingsConfigParser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/BatchingSettingsConfigParser.java @@ -15,6 +15,7 @@ package com.google.api.generator.gapic.protoparser; import com.google.api.generator.gapic.model.GapicBatchingSettings; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import java.io.File; @@ -52,6 +53,7 @@ public static Optional> parse( : Optional.empty(); } + @VisibleForTesting static Optional> parse(String gapicYamlConfigFilePath) { if (Strings.isNullOrEmpty(gapicYamlConfigFilePath) || !(new File(gapicYamlConfigFilePath)).exists()) { 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 7a6721710e..9b7a70ddd5 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 @@ -346,10 +346,16 @@ private static Field parseField(FieldDescriptor fieldDescriptor, Descriptor mess isChildType ? ResourceReference.withChildType(childTypeString) : ResourceReference.withType(typeString); - } else if (fieldDescriptor.getName().equals(ResourceNameConstants.NAME_FIELD_NAME) - && messageOptions.hasExtension(ResourceProto.resource)) { + } else if (messageOptions.hasExtension(ResourceProto.resource)) { ResourceDescriptor protoResource = messageOptions.getExtension(ResourceProto.resource); - resourceReference = ResourceReference.withType(protoResource.getType()); + // aip.dev/4231. + String resourceFieldNameValue = ResourceNameConstants.NAME_FIELD_NAME; + if (!Strings.isNullOrEmpty(protoResource.getNameField())) { + resourceFieldNameValue = protoResource.getNameField(); + } + if (fieldDescriptor.getName().equals(resourceFieldNameValue)) { + resourceReference = ResourceReference.withType(protoResource.getType()); + } } return Field.builder() diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/ResourceNameParser.java b/src/main/java/com/google/api/generator/gapic/protoparser/ResourceNameParser.java index b8ac38d2b8..b3e042752a 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/ResourceNameParser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/ResourceNameParser.java @@ -87,17 +87,17 @@ static Optional parseResourceNameFromMessageType( return Optional.empty(); } + ResourceDescriptor protoResource = messageOptions.getExtension(ResourceProto.resource); // aip.dev/4231. - Preconditions.checkNotNull( - messageTypeDescriptor.findFieldByName(ResourceNameConstants.NAME_FIELD_NAME), - String.format( - "Message %s has a resource annotation but no \"name\" field", - messageTypeDescriptor.getName())); + if (Strings.isNullOrEmpty(protoResource.getNameField())) { + Preconditions.checkNotNull( + messageTypeDescriptor.findFieldByName(ResourceNameConstants.NAME_FIELD_NAME), + String.format( + "Message %s has a resource annotation but no \"name\" field", + messageTypeDescriptor.getName())); + } - return createResourceName( - messageOptions.getExtension(ResourceProto.resource), - pakkage, - messageTypeDescriptor.getName()); + return createResourceName(protoResource, pakkage, messageTypeDescriptor.getName()); } private static Optional createResourceName( @@ -156,15 +156,16 @@ static Optional getVariableNameFromPattern(String pattern) { } else if (lastToken.equals(ResourceNameConstants.WILDCARD_PATTERN)) { resourceVariableName = null; } else { - Preconditions.checkState( - lastToken.contains("{"), - String.format( - "Pattern %s must end with a brace-encapsulated variable, e.g. {foobar}", pattern)); - Set variableNames = PathTemplate.create(pattern).vars(); - for (String variableName : variableNames) { - if (lastToken.contains(variableName)) { - resourceVariableName = variableName; - break; + // Allow singleton patterns like projects/{project}/cmekSettings. + if (!lastToken.contains("{")) { + resourceVariableName = lastToken; + } else { + Set variableNames = PathTemplate.create(pattern).vars(); + for (String variableName : variableNames) { + if (lastToken.contains(variableName)) { + resourceVariableName = variableName; + break; + } } } } 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 0dca501d54..22605dbef0 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 @@ -20,14 +20,23 @@ filegroup( srcs = ["{0}.java".format(f) for f in TESTS], ) +java_proto_library( + name = "logging_java_proto", + deps = [ + "@com_google_googleapis//google/logging/v2:logging_proto", + ], +) + [java_test( name = test_name, srcs = ["{0}.java".format(test_name)], data = [ + "//src/test/java/com/google/api/generator/gapic/testdata:gapic_config_files", "//src/test/java/com/google/api/generator/gapic/testdata:service_config_files", ], test_class = "com.google.api.generator.gapic.composer.{0}".format(test_name), deps = [ + ":logging_java_proto", "//:rpc_java_proto", "//:service_config_java_proto", "//src/main/java/com/google/api/generator/engine/ast", diff --git a/src/test/java/com/google/api/generator/gapic/composer/ServiceStubSettingsClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/ServiceStubSettingsClassComposerTest.java index 4050efe984..539648372f 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/ServiceStubSettingsClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/ServiceStubSettingsClassComposerTest.java @@ -18,50 +18,95 @@ import static junit.framework.Assert.assertTrue; import com.google.api.generator.engine.writer.JavaWriterVisitor; +import com.google.api.generator.gapic.model.GapicBatchingSettings; import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicServiceConfig; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.Service; +import com.google.api.generator.gapic.protoparser.BatchingSettingsConfigParser; import com.google.api.generator.gapic.protoparser.Parser; import com.google.api.generator.gapic.protoparser.ServiceConfigParser; +import com.google.logging.v2.LogEntryProto; +import com.google.logging.v2.LoggingConfigProto; +import com.google.logging.v2.LoggingMetricsProto; +import com.google.logging.v2.LoggingProto; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.showcase.v1beta1.EchoOuterClass; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import org.junit.Before; import org.junit.Test; public class ServiceStubSettingsClassComposerTest { - private static final String JSON_DIRECTORY = + private static final String TESTFILES_DIRECTORY = "src/test/java/com/google/api/generator/gapic/testdata/"; - private ServiceDescriptor echoService; - private FileDescriptor echoFileDescriptor; + @Test + public void generateServiceStubSettingsClasses_batchingWithEmptyResponses() { + FileDescriptor serviceFileDescriptor = LoggingProto.getDescriptor(); + ServiceDescriptor serviceDescriptor = serviceFileDescriptor.getServices().get(0); + assertEquals(serviceDescriptor.getName(), "LoggingServiceV2"); + + List protoFiles = + Arrays.asList( + serviceFileDescriptor, + LogEntryProto.getDescriptor(), + LoggingConfigProto.getDescriptor(), + LoggingMetricsProto.getDescriptor()); + + Map resourceNames = new HashMap<>(); + Map messageTypes = new HashMap<>(); + for (FileDescriptor fileDescriptor : protoFiles) { + resourceNames.putAll(Parser.parseResourceNames(fileDescriptor)); + messageTypes.putAll(Parser.parseMessages(fileDescriptor)); + } + + List services = + parseServices(serviceFileDescriptor, serviceDescriptor, messageTypes, resourceNames); + + String filename = "logging_gapic.yaml"; + Path path = Paths.get(TESTFILES_DIRECTORY, filename); + Optional> batchingSettingsOpt = + BatchingSettingsConfigParser.parse(Optional.of(path.toString())); + assertTrue(batchingSettingsOpt.isPresent()); + + String jsonFilename = "logging_grpc_service_config.json"; + Path jsonPath = Paths.get(TESTFILES_DIRECTORY, jsonFilename); + Optional configOpt = + ServiceConfigParser.parse(jsonPath.toString(), batchingSettingsOpt); + assertTrue(configOpt.isPresent()); + GapicServiceConfig config = configOpt.get(); + + Service protoService = services.get(0); + GapicClass clazz = + ServiceStubSettingsClassComposer.instance().generate(protoService, config, messageTypes); - @Before - public void setUp() { - echoFileDescriptor = EchoOuterClass.getDescriptor(); - echoService = echoFileDescriptor.getServices().get(0); - assertEquals(echoService.getName(), "Echo"); + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + assertEquals(EXPECTED_LOGGING_STUB_SETTINGS_STRING, visitor.write()); } @Test - public void generateServiceClasses() { + public void generateServiceStubSettingsClasses_basic() { + FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); + ServiceDescriptor echoServiceDescriptor = echoFileDescriptor.getServices().get(0); + assertEquals(echoServiceDescriptor.getName(), "Echo"); + Map messageTypes = Parser.parseMessages(echoFileDescriptor); Map resourceNames = Parser.parseResourceNames(echoFileDescriptor); - Set outputResourceNames = new HashSet<>(); List services = - Parser.parseService(echoFileDescriptor, messageTypes, resourceNames, outputResourceNames); + parseServices(echoFileDescriptor, echoServiceDescriptor, messageTypes, resourceNames); String jsonFilename = "showcase_grpc_service_config.json"; - Path jsonPath = Paths.get(JSON_DIRECTORY, jsonFilename); + Path jsonPath = Paths.get(TESTFILES_DIRECTORY, jsonFilename); Optional configOpt = ServiceConfigParser.parse(jsonPath.toString(), Optional.empty()); assertTrue(configOpt.isPresent()); @@ -74,11 +119,21 @@ public void generateServiceClasses() { JavaWriterVisitor visitor = new JavaWriterVisitor(); clazz.classDefinition().accept(visitor); - assertEquals(EXPECTED_CLASS_STRING, visitor.write()); + assertEquals(EXPECTED_ECHO_STUB_SETTINGS_STRING, visitor.write()); + } + + private static List parseServices( + FileDescriptor protoFileDescriptor, + ServiceDescriptor serviceDescriptor, + Map messageTypes, + Map resourceNames) { + Set outputResourceNames = new HashSet<>(); + return Parser.parseService( + protoFileDescriptor, messageTypes, resourceNames, outputResourceNames); } // TODO(miraleung): Update this when a file-diffing test mechanism is in place. - private static final String EXPECTED_CLASS_STRING = + private static final String EXPECTED_ECHO_STUB_SETTINGS_STRING = "package com.google.showcase.v1beta1.stub;\n" + "\n" + "import static com.google.showcase.v1beta1.EchoClient.PagedExpandPagedResponse;\n" @@ -571,4 +626,593 @@ public void generateServiceClasses() { + " }\n" + " }\n" + "}\n"; + + private static final String EXPECTED_LOGGING_STUB_SETTINGS_STRING = + "package com.google.logging.v2.stub;\n" + + "\n" + + "import static" + + " com.google.logging.v2.LoggingServiceV2Client.ListLogEntriesPagedResponse;\n" + + "import static com.google.logging.v2.LoggingServiceV2Client.ListLogsPagedResponse;\n" + + "import static" + + " com.google.logging.v2.LoggingServiceV2Client.ListMonitoredResourceDescriptorsPagedResponse;\n" + + "\n" + + "import com.google.api.MonitoredResourceDescriptor;\n" + + "import com.google.api.core.ApiFunction;\n" + + "import com.google.api.core.ApiFuture;\n" + + "import com.google.api.core.BetaApi;\n" + + "import com.google.api.gax.core.GaxProperties;\n" + + "import com.google.api.gax.core.GoogleCredentialsProvider;\n" + + "import com.google.api.gax.core.InstantiatingExecutorProvider;\n" + + "import com.google.api.gax.grpc.GaxGrpcProperties;\n" + + "import com.google.api.gax.grpc.GrpcTransportChannel;\n" + + "import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;\n" + + "import com.google.api.gax.retrying.RetrySettings;\n" + + "import com.google.api.gax.rpc.ApiCallContext;\n" + + "import com.google.api.gax.rpc.ApiClientHeaderProvider;\n" + + "import com.google.api.gax.rpc.ClientContext;\n" + + "import com.google.api.gax.rpc.PageContext;\n" + + "import com.google.api.gax.rpc.PagedCallSettings;\n" + + "import com.google.api.gax.rpc.PagedListDescriptor;\n" + + "import com.google.api.gax.rpc.PagedListResponseFactory;\n" + + "import com.google.api.gax.rpc.StatusCode;\n" + + "import com.google.api.gax.rpc.StubSettings;\n" + + "import com.google.api.gax.rpc.TransportChannelProvider;\n" + + "import com.google.api.gax.rpc.UnaryCallSettings;\n" + + "import com.google.api.gax.rpc.UnaryCallable;\n" + + "import com.google.common.collect.ImmutableList;\n" + + "import com.google.common.collect.ImmutableMap;\n" + + "import com.google.common.collect.ImmutableSet;\n" + + "import com.google.common.collect.Lists;\n" + + "import com.google.logging.v2.DeleteLogRequest;\n" + + "import com.google.logging.v2.ListLogEntriesRequest;\n" + + "import com.google.logging.v2.ListLogEntriesResponse;\n" + + "import com.google.logging.v2.ListLogsRequest;\n" + + "import com.google.logging.v2.ListLogsResponse;\n" + + "import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest;\n" + + "import com.google.logging.v2.ListMonitoredResourceDescriptorsResponse;\n" + + "import com.google.logging.v2.LogEntry;\n" + + "import com.google.logging.v2.WriteLogEntriesRequest;\n" + + "import com.google.logging.v2.WriteLogEntriesResponse;\n" + + "import com.google.protobuf.Empty;\n" + + "import java.io.IOException;\n" + + "import java.util.List;\n" + + "import java.util.Objects;\n" + + "import javax.annotation.Generated;\n" + + "import org.threeten.bp.Duration;\n" + + "\n" + + "@BetaApi\n" + + "@Generated(\"by gapic-generator-java\")\n" + + "public class LoggingServiceV2StubSettings extends" + + " StubSettings {\n" + + " private static final ImmutableList DEFAULT_SERVICE_SCOPES =\n" + + " ImmutableList.builder()\n" + + " .add(\"https://www.googleapis.com/auth/cloud-platform\")\n" + + " .add(\"https://www.googleapis.com/auth/cloud-platform.read-only\")\n" + + " .add(\"https://www.googleapis.com/auth/logging.admin\")\n" + + " .add(\"https://www.googleapis.com/auth/logging.read\")\n" + + " .add(\"https://www.googleapis.com/auth/logging.write\")\n" + + " .build();\n" + + " private final UnaryCallSettings deleteLogSettings;\n" + + " private final UnaryCallSettings\n" + + " writeLogEntriesSettings;\n" + + " private final PagedCallSettings<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>\n" + + " listLogEntriesSettings;\n" + + " private final PagedCallSettings<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>\n" + + " listMonitoredResourceDescriptorsSettings;\n" + + " private final PagedCallSettings\n" + + " listLogsSettings;\n" + + " private static final PagedListDescriptor\n" + + " LIST_LOG_ENTRIES_PAGE_STR_DESC =\n" + + " new PagedListDescriptor() {\n" + + " @Override\n" + + " public String emptyToken() {\n" + + " return \"\";\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListLogEntriesRequest injectToken(ListLogEntriesRequest payload," + + " String token) {\n" + + " return" + + " ListLogEntriesRequest.newBuilder(payload).setPageToken(token).build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListLogEntriesRequest injectPageSize(\n" + + " ListLogEntriesRequest payload, int pageSize) {\n" + + " return" + + " ListLogEntriesRequest.newBuilder(payload).setPageSize(pageSize).build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Integer extractPageSize(ListLogEntriesRequest payload) {\n" + + " return payload.getPageSize();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public String extractNextToken(ListLogEntriesResponse payload) {\n" + + " return payload.getNextPageToken();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Iterable extractResources(ListLogEntriesResponse" + + " payload) {\n" + + " return Objects.equals(payload.getResponsesList(), null)\n" + + " ? ImmutableList.of()\n" + + " : payload.getResponsesList();\n" + + " }\n" + + " };\n" + + " private static final PagedListDescriptor<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " MonitoredResourceDescriptor>\n" + + " LIST_MONITORED_RESOURCE_DESCRIPTORS_PAGE_STR_DESC =\n" + + " new PagedListDescriptor<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " MonitoredResourceDescriptor>() {\n" + + " @Override\n" + + " public String emptyToken() {\n" + + " return \"\";\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListMonitoredResourceDescriptorsRequest injectToken(\n" + + " ListMonitoredResourceDescriptorsRequest payload, String token) {\n" + + " return ListMonitoredResourceDescriptorsRequest.newBuilder(payload)\n" + + " .setPageToken(token)\n" + + " .build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListMonitoredResourceDescriptorsRequest injectPageSize(\n" + + " ListMonitoredResourceDescriptorsRequest payload, int pageSize) {\n" + + " return ListMonitoredResourceDescriptorsRequest.newBuilder(payload)\n" + + " .setPageSize(pageSize)\n" + + " .build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Integer extractPageSize(ListMonitoredResourceDescriptorsRequest" + + " payload) {\n" + + " return payload.getPageSize();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public String extractNextToken(ListMonitoredResourceDescriptorsResponse" + + " payload) {\n" + + " return payload.getNextPageToken();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Iterable extractResources(\n" + + " ListMonitoredResourceDescriptorsResponse payload) {\n" + + " return Objects.equals(payload.getResponsesList(), null)\n" + + " ? ImmutableList.of()\n" + + " : payload.getResponsesList();\n" + + " }\n" + + " };\n" + + " private static final PagedListDescriptor\n" + + " LIST_LOGS_PAGE_STR_DESC =\n" + + " new PagedListDescriptor() {\n" + + " @Override\n" + + " public String emptyToken() {\n" + + " return \"\";\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListLogsRequest injectToken(ListLogsRequest payload, String token)" + + " {\n" + + " return" + + " ListLogsRequest.newBuilder(payload).setPageToken(token).build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ListLogsRequest injectPageSize(ListLogsRequest payload, int" + + " pageSize) {\n" + + " return" + + " ListLogsRequest.newBuilder(payload).setPageSize(pageSize).build();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Integer extractPageSize(ListLogsRequest payload) {\n" + + " return payload.getPageSize();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public String extractNextToken(ListLogsResponse payload) {\n" + + " return payload.getNextPageToken();\n" + + " }\n" + + "\n" + + " @Override\n" + + " public Iterable extractResources(ListLogsResponse payload) {\n" + + " return Objects.equals(payload.getResponsesList(), null)\n" + + " ? ImmutableList.of()\n" + + " : payload.getResponsesList();\n" + + " }\n" + + " };\n" + + " private static final PagedListResponseFactory<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>\n" + + " LIST_LOG_ENTRIES_PAGE_STR_FACT =\n" + + " new PagedListResponseFactory<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>() {\n" + + " @Override\n" + + " public ApiFuture getFuturePagedResponse(\n" + + " UnaryCallable" + + " callable,\n" + + " ListLogEntriesRequest request,\n" + + " ApiCallContext context,\n" + + " ApiFuture futureResponse) {\n" + + " PageContext" + + " pageContext =\n" + + " PageContext.create(callable, LIST_LOG_ENTRIES_PAGE_STR_DESC," + + " request, context);\n" + + " return ListLogEntriesPagedResponse.createAsync(pageContext," + + " futureResponse);\n" + + " }\n" + + " };\n" + + " private static final PagedListResponseFactory<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>\n" + + " LIST_MONITORED_RESOURCE_DESCRIPTORS_PAGE_STR_FACT =\n" + + " new PagedListResponseFactory<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>() {\n" + + " @Override\n" + + " public ApiFuture" + + " getFuturePagedResponse(\n" + + " UnaryCallable<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse>\n" + + " callable,\n" + + " ListMonitoredResourceDescriptorsRequest request,\n" + + " ApiCallContext context,\n" + + " ApiFuture futureResponse)" + + " {\n" + + " PageContext<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " MonitoredResourceDescriptor>\n" + + " pageContext =\n" + + " PageContext.create(\n" + + " callable,\n" + + " LIST_MONITORED_RESOURCE_DESCRIPTORS_PAGE_STR_DESC,\n" + + " request,\n" + + " context);\n" + + " return ListMonitoredResourceDescriptorsPagedResponse.createAsync(\n" + + " pageContext, futureResponse);\n" + + " }\n" + + " };\n" + + " private static final PagedListResponseFactory<\n" + + " ListLogsRequest, ListLogsResponse, ListLogsPagedResponse>\n" + + " LIST_LOGS_PAGE_STR_FACT =\n" + + " new PagedListResponseFactory() {\n" + + " @Override\n" + + " public ApiFuture getFuturePagedResponse(\n" + + " UnaryCallable callable,\n" + + " ListLogsRequest request,\n" + + " ApiCallContext context,\n" + + " ApiFuture futureResponse) {\n" + + " PageContext pageContext =\n" + + " PageContext.create(callable, LIST_LOGS_PAGE_STR_DESC, request," + + " context);\n" + + " return ListLogsPagedResponse.createAsync(pageContext," + + " futureResponse);\n" + + " }\n" + + " };\n" + + "\n" + + " public UnaryCallSettings deleteLogSettings() {\n" + + " return deleteLogSettings;\n" + + " }\n" + + "\n" + + " public UnaryCallSettings\n" + + " writeLogEntriesSettings() {\n" + + " return writeLogEntriesSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>\n" + + " listLogEntriesSettings() {\n" + + " return listLogEntriesSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>\n" + + " listMonitoredResourceDescriptorsSettings() {\n" + + " return listMonitoredResourceDescriptorsSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings\n" + + " listLogsSettings() {\n" + + " return listLogsSettings;\n" + + " }\n" + + "\n" + + " @BetaApi(\"A restructuring of stub classes is planned, so this may break in the" + + " future\")\n" + + " public LoggingServiceV2Stub createStub() throws IOException {\n" + + " if (getTransportChannelProvider()\n" + + " .getTransportName()\n" + + " .equals(GrpcTransportChannel.getGrpcTransportName())) {\n" + + " return GrpcLoggingServiceV2Stub.create(this);\n" + + " }\n" + + " throw new UnsupportedOperationException(\n" + + " String.format(\n" + + " \"Transport not supported: %s\"," + + " getTransportChannelProvider().getTransportName()));\n" + + " }\n" + + "\n" + + " public static InstantiatingExecutorProvider.Builder" + + " defaultExecutorProviderBuilder() {\n" + + " return InstantiatingExecutorProvider.newBuilder();\n" + + " }\n" + + "\n" + + " public static String getDefaultEndpoint() {\n" + + " return \"logging.googleapis.com:443\";\n" + + " }\n" + + "\n" + + " public static List getDefaultServiceScopes() {\n" + + " return DEFAULT_SERVICE_SCOPES;\n" + + " }\n" + + "\n" + + " public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder()" + + " {\n" + + " return" + + " GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES);\n" + + " }\n" + + "\n" + + " public static InstantiatingGrpcChannelProvider.Builder" + + " defaultGrpcTransportProviderBuilder() {\n" + + " return InstantiatingGrpcChannelProvider.newBuilder()\n" + + " .setMaxInboundMessageSize(Integer.MAX_VALUE);\n" + + " }\n" + + "\n" + + " public static TransportChannelProvider defaultTransportChannelProvider() {\n" + + " return defaultGrpcTransportProviderBuilder().build();\n" + + " }\n" + + "\n" + + " @BetaApi(\"The surface for customizing headers is not stable yet and may change in" + + " the future.\")\n" + + " public static ApiClientHeaderProvider.Builder" + + " defaultApiClientHeaderProviderBuilder() {\n" + + " return ApiClientHeaderProvider.newBuilder()\n" + + " .setGeneratedLibToken(\n" + + " \"gapic\"," + + " GaxProperties.getLibraryVersion(LoggingServiceV2StubSettings.class))\n" + + " .setTransportToken(\n" + + " GaxGrpcProperties.getGrpcTokenName()," + + " GaxGrpcProperties.getGrpcVersion());\n" + + " }\n" + + "\n" + + " public static Builder newBuilder() {\n" + + " return Builder.createDefault();\n" + + " }\n" + + "\n" + + " public static Builder newBuilder(ClientContext clientContext) {\n" + + " return new Builder(clientContext);\n" + + " }\n" + + "\n" + + " public Builder toBuilder() {\n" + + " return new Builder(this);\n" + + " }\n" + + "\n" + + " protected LoggingServiceV2StubSettings(Builder settingsBuilder) throws IOException" + + " {\n" + + " super(settingsBuilder);\n" + + " deleteLogSettings = settingsBuilder.deleteLogSettings().build();\n" + + " writeLogEntriesSettings = settingsBuilder.writeLogEntriesSettings().build();\n" + + " listLogEntriesSettings = settingsBuilder.listLogEntriesSettings().build();\n" + + " listMonitoredResourceDescriptorsSettings =\n" + + " settingsBuilder.listMonitoredResourceDescriptorsSettings().build();\n" + + " listLogsSettings = settingsBuilder.listLogsSettings().build();\n" + + " }\n" + + "\n" + + " public static class Builder extends StubSettings.Builder {\n" + + " private final ImmutableList>" + + " unaryMethodSettingsBuilders;\n" + + " private final UnaryCallSettings.Builder" + + " deleteLogSettings;\n" + + " private final UnaryCallSettings.Builder\n" + + " writeLogEntriesSettings;\n" + + " private final PagedCallSettings.Builder<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>\n" + + " listLogEntriesSettings;\n" + + " private final PagedCallSettings.Builder<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>\n" + + " listMonitoredResourceDescriptorsSettings;\n" + + " private final PagedCallSettings.Builder<\n" + + " ListLogsRequest, ListLogsResponse, ListLogsPagedResponse>\n" + + " listLogsSettings;\n" + + " private static final ImmutableMap>\n" + + " RETRYABLE_CODE_DEFINITIONS;\n" + + "\n" + + " static {\n" + + " ImmutableMap.Builder> definitions =\n" + + " ImmutableMap.builder();\n" + + " definitions.put(\n" + + " \"retry_policy_1_codes\",\n" + + " ImmutableSet.copyOf(\n" + + " Lists.newArrayList(\n" + + " StatusCode.Code.DEADLINE_EXCEEDED,\n" + + " StatusCode.Code.INTERNAL,\n" + + " StatusCode.Code.UNAVAILABLE)));\n" + + " RETRYABLE_CODE_DEFINITIONS = definitions.build();\n" + + " }\n" + + "\n" + + " private static final ImmutableMap" + + " RETRY_PARAM_DEFINITIONS;\n" + + "\n" + + " static {\n" + + " ImmutableMap.Builder definitions =" + + " ImmutableMap.builder();\n" + + " RetrySettings settings = null;\n" + + " settings =\n" + + " RetrySettings.newBuilder()\n" + + " .setInitialRetryDelay(Duration.ofMillis(100L))\n" + + " .setRetryDelayMultiplier(1.3)\n" + + " .setMaxRetryDelay(Duration.ofMillis(60000L))\n" + + " .setInitialRpcTimeout(Duration.ofMillis(60000L))\n" + + " .setRpcTimeoutMultiplier(1.0)\n" + + " .setMaxRpcTimeout(Duration.ofMillis(60000L))\n" + + " .setTotalTimeout(Duration.ofMillis(60000L))\n" + + " .build();\n" + + " definitions.put(\"retry_policy_1_params\", settings);\n" + + " RETRY_PARAM_DEFINITIONS = definitions.build();\n" + + " }\n" + + "\n" + + " protected Builder() {\n" + + " this(((ClientContext) null));\n" + + " }\n" + + "\n" + + " protected Builder(ClientContext clientContext) {\n" + + " super(clientContext);\n" + + " deleteLogSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();\n" + + " writeLogEntriesSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();\n" + + " listLogEntriesSettings =" + + " PagedCallSettings.newBuilder(LIST_LOG_ENTRIES_PAGE_STR_FACT);\n" + + " listMonitoredResourceDescriptorsSettings =\n" + + " " + + " PagedCallSettings.newBuilder(LIST_MONITORED_RESOURCE_DESCRIPTORS_PAGE_STR_FACT);\n" + + " listLogsSettings = PagedCallSettings.newBuilder(LIST_LOGS_PAGE_STR_FACT);\n" + + " unaryMethodSettingsBuilders =\n" + + " ImmutableList.>of(\n" + + " deleteLogSettings,\n" + + " writeLogEntriesSettings,\n" + + " listLogEntriesSettings,\n" + + " listMonitoredResourceDescriptorsSettings,\n" + + " listLogsSettings);\n" + + " initDefaults(this);\n" + + " }\n" + + "\n" + + " protected Builder(LoggingServiceV2StubSettings settings) {\n" + + " super(settings);\n" + + " deleteLogSettings = settings.deleteLogSettings.toBuilder();\n" + + " writeLogEntriesSettings = settings.writeLogEntriesSettings.toBuilder();\n" + + " listLogEntriesSettings = settings.listLogEntriesSettings.toBuilder();\n" + + " listMonitoredResourceDescriptorsSettings =\n" + + " settings.listMonitoredResourceDescriptorsSettings.toBuilder();\n" + + " listLogsSettings = settings.listLogsSettings.toBuilder();\n" + + " unaryMethodSettingsBuilders =\n" + + " ImmutableList.>of(\n" + + " deleteLogSettings,\n" + + " writeLogEntriesSettings,\n" + + " listLogEntriesSettings,\n" + + " listMonitoredResourceDescriptorsSettings,\n" + + " listLogsSettings);\n" + + " }\n" + + "\n" + + " private static Builder createDefault() {\n" + + " Builder builder = new Builder(((ClientContext) null));\n" + + " builder.setTransportChannelProvider(defaultTransportChannelProvider());\n" + + " builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build());\n" + + " " + + " builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build());\n" + + " builder.setEndpoint(getDefaultEndpoint());\n" + + " return initDefaults(builder);\n" + + " }\n" + + "\n" + + " private static Builder initDefaults(Builder builder) {\n" + + " builder\n" + + " .deleteLogSettings()\n" + + " " + + " .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get(\"retry_policy_1_codes\"))\n" + + " " + + " .setRetrySettings(RETRY_PARAM_DEFINITIONS.get(\"retry_policy_1_params\"));\n" + + " builder\n" + + " .writeLogEntriesSettings()\n" + + " " + + " .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get(\"retry_policy_1_codes\"))\n" + + " " + + " .setRetrySettings(RETRY_PARAM_DEFINITIONS.get(\"retry_policy_1_params\"));\n" + + " builder\n" + + " .listLogEntriesSettings()\n" + + " " + + " .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get(\"retry_policy_1_codes\"))\n" + + " " + + " .setRetrySettings(RETRY_PARAM_DEFINITIONS.get(\"retry_policy_1_params\"));\n" + + " builder\n" + + " .listMonitoredResourceDescriptorsSettings()\n" + + " " + + " .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get(\"retry_policy_1_codes\"))\n" + + " " + + " .setRetrySettings(RETRY_PARAM_DEFINITIONS.get(\"retry_policy_1_params\"));\n" + + " builder\n" + + " .listLogsSettings()\n" + + " " + + " .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get(\"retry_policy_1_codes\"))\n" + + " " + + " .setRetrySettings(RETRY_PARAM_DEFINITIONS.get(\"retry_policy_1_params\"));\n" + + " return builder;\n" + + " }\n" + + "\n" + + " public Builder applyToAllUnaryMethods(\n" + + " ApiFunction, Void> settingsUpdater) throws" + + " Exception {\n" + + " super.applyToAllUnaryMethods(unaryMethodSettingsBuilders, settingsUpdater);\n" + + " return this;\n" + + " }\n" + + "\n" + + " public ImmutableList>" + + " unaryMethodSettingsBuilders() {\n" + + " return unaryMethodSettingsBuilders;\n" + + " }\n" + + "\n" + + " public UnaryCallSettings.Builder deleteLogSettings() {\n" + + " return deleteLogSettings;\n" + + " }\n" + + "\n" + + " public UnaryCallSettings.Builder\n" + + " writeLogEntriesSettings() {\n" + + " return writeLogEntriesSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings.Builder<\n" + + " ListLogEntriesRequest, ListLogEntriesResponse," + + " ListLogEntriesPagedResponse>\n" + + " listLogEntriesSettings() {\n" + + " return listLogEntriesSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings.Builder<\n" + + " ListMonitoredResourceDescriptorsRequest,\n" + + " ListMonitoredResourceDescriptorsResponse,\n" + + " ListMonitoredResourceDescriptorsPagedResponse>\n" + + " listMonitoredResourceDescriptorsSettings() {\n" + + " return listMonitoredResourceDescriptorsSettings;\n" + + " }\n" + + "\n" + + " public PagedCallSettings.Builder\n" + + " listLogsSettings() {\n" + + " return listLogsSettings;\n" + + " }\n" + + "\n" + + " @Override\n" + + " public LoggingServiceV2StubSettings build() throws IOException {\n" + + " return new LoggingServiceV2StubSettings(this);\n" + + " }\n" + + " }\n" + + "}\n"; } diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/ResourceNameParserTest.java b/src/test/java/com/google/api/generator/gapic/protoparser/ResourceNameParserTest.java index 4c07b1b6f0..7bb6c1fe29 100644 --- a/src/test/java/com/google/api/generator/gapic/protoparser/ResourceNameParserTest.java +++ b/src/test/java/com/google/api/generator/gapic/protoparser/ResourceNameParserTest.java @@ -191,17 +191,19 @@ public void getVariableName_differentCasedName() { } @Test - public void getVariableName_badEndingLiteral() { - assertThrows( - IllegalStateException.class, - () -> ResourceNameParser.getVariableNameFromPattern("projects/{project}/badLiteral")); + public void getVariableName_singletonEnding() { + Optional nameOpt = + ResourceNameParser.getVariableNameFromPattern("projects/{project}/cmekSettings"); + assertTrue(nameOpt.isPresent()); + assertEquals("cmekSettings", nameOpt.get()); } @Test public void getVariableName_onlyLiterals() { - assertThrows( - IllegalStateException.class, - () -> ResourceNameParser.getVariableNameFromPattern("projects/project/locations/location")); + Optional nameOpt = + ResourceNameParser.getVariableNameFromPattern("projects/project/locations/location"); + assertTrue(nameOpt.isPresent()); + assertEquals("location", nameOpt.get()); } @Test diff --git a/src/test/java/com/google/api/generator/gapic/testdata/logging_grpc_service_config.json b/src/test/java/com/google/api/generator/gapic/testdata/logging_grpc_service_config.json new file mode 100644 index 0000000000..fc9c085b42 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/testdata/logging_grpc_service_config.json @@ -0,0 +1,162 @@ +{ + "methodConfig": [ + { + "name": [ + { + "service": "google.logging.v2.MetricsServiceV2", + "method": "CreateLogMetric" + } + ], + "timeout": "60s" + }, + { + "name": [ + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "DeleteLog" + }, + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "WriteLogEntries" + }, + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "ListLogEntries" + }, + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "ListMonitoredResourceDescriptors" + }, + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "ListLogs" + } + ], + "timeout": "60s", + "retryPolicy": { + "maxAttempts": 5, + "initialBackoff": "0.100s", + "maxBackoff": "60s", + "backoffMultiplier": 1.3, + "retryableStatusCodes": [ + "DEADLINE_EXCEEDED", + "INTERNAL", + "UNAVAILABLE" + ] + } + }, + { + "name": [ + { + "service": "google.logging.v2.LoggingServiceV2", + "method": "TailLogEntries" + } + ], + "timeout": "3600s", + "retryPolicy": { + "maxAttempts": 5, + "initialBackoff": "0.100s", + "maxBackoff": "60s", + "backoffMultiplier": 1.3, + "retryableStatusCodes": [ + "DEADLINE_EXCEEDED", + "INTERNAL", + "UNAVAILABLE" + ] + } + }, + { + "name": [ + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "ListSinks" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "GetSink" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "UpdateSink" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "DeleteSink" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "ListExclusions" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "GetExclusion" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "DeleteExclusion" + } + ], + "timeout": "60s", + "retryPolicy": { + "maxAttempts": 5, + "initialBackoff": "0.100s", + "maxBackoff": "60s", + "backoffMultiplier": 1.3, + "retryableStatusCodes": [ + "DEADLINE_EXCEEDED", + "INTERNAL", + "UNAVAILABLE" + ] + } + }, + { + "name": [ + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "CreateSink" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "CreateExclusion" + }, + { + "service": "google.logging.v2.ConfigServiceV2", + "method": "UpdateExclusion" + } + ], + "timeout": "120s" + }, + { + "name": [ + { + "service": "google.logging.v2.MetricsServiceV2", + "method": "ListLogMetrics" + }, + { + "service": "google.logging.v2.MetricsServiceV2", + "method": "GetLogMetric" + }, + { + "service": "google.logging.v2.MetricsServiceV2", + "method": "UpdateLogMetric" + }, + { + "service": "google.logging.v2.MetricsServiceV2", + "method": "DeleteLogMetric" + } + ], + "timeout": "60s", + "retryPolicy": { + "maxAttempts": 5, + "initialBackoff": "0.100s", + "maxBackoff": "60s", + "backoffMultiplier": 1.3, + "retryableStatusCodes": [ + "DEADLINE_EXCEEDED", + "INTERNAL", + "UNAVAILABLE" + ] + } + } + ] +}