Skip to content

Commit

Permalink
[ggj][codegen][test] feat: add rpcExceptionTest for RPCs w/o overload…
Browse files Browse the repository at this point in the history
…s, support LRO (#349)

* fix!: refactor field into MethodArgument, add enum/msg flags

* feat: partial isAssignableFrom VaporRef support, enable full-name type usage

* feat: support negative numeric literals

* fix: separate resname tokenizing from class composer

* feat: add per-type default value composer

* feat: add ServiceClientTest.methodExceptionTests codegen

* feat: add rpcExceptionTest for RPCs w/o overloads, support LRO

* fix: CI merge
  • Loading branch information
miraleung authored Sep 26, 2020
1 parent d221f8b commit a0d4de5
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 25 deletions.
4 changes: 2 additions & 2 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package(default_visibility = ["//visibility:public"])

load(
"//:gapic_generator_java.bzl",
"google_java_format",
"google_java_format_verification",
)

package(default_visibility = ["//visibility:public"])

JAVA_SRCS = [
"//src/main/java/com/google/api/generator:generator_files",
"//src/main/java/com/google/api/generator/engine:engine_files",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.ast.ValueExpr;
import com.google.api.generator.gapic.model.Field;
import com.google.api.generator.gapic.model.Message;
import com.google.api.generator.gapic.model.MethodArgument;
import com.google.api.generator.gapic.model.ResourceName;
import com.google.api.generator.gapic.utils.JavaStyle;
Expand Down Expand Up @@ -186,4 +187,54 @@ static Expr createDefaultValue(ResourceName resourceName, List<ResourceName> res
.setReturnType(resourceNameJavaType)
.build();
}

static Expr createSimpleMessageBuilderExpr(
Message message, Map<String, ResourceName> resourceNames, Map<String, Message> messageTypes) {
MethodInvocationExpr builderExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(message.type())
.setMethodName("newBuilder")
.build();
for (Field field : message.fields()) {
if (field.isContainedInOneof() // Avoid colliding fields.
|| ((field.isMessage() || field.isEnum()) // Avoid importing unparsed messages.
&& !field.isRepeated()
&& !messageTypes.containsKey(field.type().reference().name()))) {
continue;
}
String setterMethodNamePattern = "set%s";
if (field.isRepeated()) {
setterMethodNamePattern = field.isMap() ? "putAll%s" : "addAll%s";
}
Expr defaultExpr = null;
if (field.hasResourceReference()
&& resourceNames.get(field.resourceReference().resourceTypeString()) != null) {
defaultExpr =
createDefaultValue(
resourceNames.get(field.resourceReference().resourceTypeString()),
resourceNames.values().stream().collect(Collectors.toList()));
defaultExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(defaultExpr)
.setMethodName("toString")
.setReturnType(TypeNode.STRING)
.build();
} else {
defaultExpr = createDefaultValue(field);
}
builderExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(builderExpr)
.setMethodName(
String.format(setterMethodNamePattern, JavaStyle.toUpperCamelCase(field.name())))
.setArguments(defaultExpr)
.build();
}

return MethodInvocationExpr.builder()
.setExprReferenceExpr(builderExpr)
.setMethodName("build")
.setReturnType(message.type())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.google.api.gax.rpc.UnaryCallSettings;
import com.google.api.generator.engine.ast.AnnotationNode;
import com.google.api.generator.engine.ast.AssignmentExpr;
import com.google.api.generator.engine.ast.CastExpr;
import com.google.api.generator.engine.ast.ClassDefinition;
import com.google.api.generator.engine.ast.CommentStatement;
import com.google.api.generator.engine.ast.ConcreteReference;
Expand Down Expand Up @@ -69,6 +70,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -403,15 +405,26 @@ private static List<MethodDefinition> createTestMethods(
Map<String, Message> messageTypes) {
List<MethodDefinition> javaMethods = new ArrayList<>();
for (Method method : service.methods()) {
for (int i = 0; i < method.methodSignatures().size(); i++) {
if (method.methodSignatures().isEmpty()) {
javaMethods.add(
createRpcExceptionTestMethod(
method,
method.methodSignatures().get(i),
i,
Collections.emptyList(),
0,
classMemberVarExprs,
resourceNames,
messageTypes));
} else {
for (int i = 0; i < method.methodSignatures().size(); i++) {
javaMethods.add(
createRpcExceptionTestMethod(
method,
method.methodSignatures().get(i),
i,
classMemberVarExprs,
resourceNames,
messageTypes));
}
}
}
return javaMethods;
Expand Down Expand Up @@ -462,25 +475,74 @@ private static MethodDefinition createRpcExceptionTestMethod(

List<VariableExpr> argVarExprs = new ArrayList<>();
List<Expr> tryBodyExprs = new ArrayList<>();
for (MethodArgument methodArg : methodSignature) {
if (methodSignature.isEmpty()) {
// Construct the actual request.
VariableExpr varExpr =
VariableExpr.withVariable(
Variable.builder().setType(methodArg.type()).setName(methodArg.name()).build());
Variable.builder().setType(method.inputType()).setName("request").build());
argVarExprs.add(varExpr);
Expr valExpr = DefaultValueComposer.createDefaultValue(methodArg, resourceNames);
Message requestMessage = messageTypes.get(method.inputType().reference().name());
Preconditions.checkNotNull(requestMessage);
Expr valExpr =
DefaultValueComposer.createSimpleMessageBuilderExpr(
requestMessage, resourceNames, messageTypes);
tryBodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(varExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(valExpr)
.build());
// TODO(miraleung): Empty line here.
} else {
for (MethodArgument methodArg : methodSignature) {
VariableExpr varExpr =
VariableExpr.withVariable(
Variable.builder().setType(methodArg.type()).setName(methodArg.name()).build());
argVarExprs.add(varExpr);
Expr valExpr = DefaultValueComposer.createDefaultValue(methodArg, resourceNames);
tryBodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(varExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(valExpr)
.build());
// TODO(miraleung): Empty line here.
}
}
tryBodyExprs.add(
String rpcJavaName = JavaStyle.toLowerCamelCase(method.name());
if (method.hasLro()) {
rpcJavaName += "Async";
}
MethodInvocationExpr rpcJavaMethodInvocationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(classMemberVarExprs.get("client"))
.setMethodName(JavaStyle.toLowerCamelCase(method.name()))
.setMethodName(rpcJavaName)
.setArguments(argVarExprs.stream().map(e -> (Expr) e).collect(Collectors.toList()))
.build());
.build();
if (method.hasLro()) {
rpcJavaMethodInvocationExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(rpcJavaMethodInvocationExpr)
.setMethodName("get")
.build();
}
tryBodyExprs.add(rpcJavaMethodInvocationExpr);

VariableExpr catchExceptionVarExpr =
VariableExpr.builder()
.setVariable(
Variable.builder()
.setType(
TypeNode.withExceptionClazz(
method.hasLro()
? ExecutionException.class
: InvalidArgumentException.class))
.setName("e")
.build())
.build();

List<Statement> catchBody =
method.hasLro()
? createRpcLroExceptionTestCatchBody(catchExceptionVarExpr)
: Arrays.asList(
CommentStatement.withComment(LineComment.withComment("Expected exception.")));

// Assert a failure if no exception was raised.
tryBodyExprs.add(
Expand All @@ -496,18 +558,8 @@ private static MethodDefinition createRpcExceptionTestMethod(
tryBodyExprs.stream()
.map(e -> ExprStatement.withExpr(e))
.collect(Collectors.toList()))
.setCatchVariableExpr(
VariableExpr.builder()
.setVariable(
Variable.builder()
.setType(TypeNode.withExceptionClazz(InvalidArgumentException.class))
.setName("e")
.build())
.setIsDecl(true)
.build())
.setCatchBody(
Arrays.asList(
CommentStatement.withComment(LineComment.withComment("Expected exception."))))
.setCatchVariableExpr(catchExceptionVarExpr.toBuilder().setIsDecl(true).build())
.setCatchBody(catchBody)
.build();

return MethodDefinition.builder()
Expand All @@ -524,6 +576,87 @@ private static MethodDefinition createRpcExceptionTestMethod(
.build();
}

private static List<Statement> createRpcLroExceptionTestCatchBody(VariableExpr exceptionExpr) {
List<Expr> catchBodyExprs = new ArrayList<>();

Expr testExpectedValueExpr =
VariableExpr.builder()
.setVariable(
Variable.builder()
.setType(TypeNode.withReference(ConcreteReference.withClazz(Class.class)))
.setName("class")
.build())
.setStaticReferenceType(STATIC_TYPES.get("InvalidArgumentException"))
.build();
Expr getCauseExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(exceptionExpr)
.setMethodName("getCause")
.setReturnType(TypeNode.withReference(ConcreteReference.withClazz(Throwable.class)))
.build();
Expr testActualValueExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(getCauseExpr)
.setMethodName("getClass")
.build();

// Constructs `Assert.assertEquals(InvalidArgumentException.class, e.getCaus().getClass());`.
catchBodyExprs.add(
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("Assert"))
.setMethodName("assertEquals")
.setArguments(testExpectedValueExpr, testActualValueExpr)
.build());

// Construct the apiException variable.
VariableExpr apiExceptionVarExpr =
VariableExpr.withVariable(
Variable.builder()
.setType(STATIC_TYPES.get("InvalidArgumentException"))
.setName("apiException")
.build());
Expr castedCauseExpr =
CastExpr.builder()
.setType(STATIC_TYPES.get("InvalidArgumentException"))
.setExpr(getCauseExpr)
.build();
catchBodyExprs.add(
AssignmentExpr.builder()
.setVariableExpr(apiExceptionVarExpr.toBuilder().setIsDecl(true).build())
.setValueExpr(castedCauseExpr)
.build());

// Construct the last assert statement.
testExpectedValueExpr =
EnumRefExpr.builder()
.setType(
TypeNode.withReference(
ConcreteReference.builder()
.setClazz(StatusCode.Code.class)
.setIsStaticImport(false)
.build()))
.setName("INVALID_ARGUMENT")
.build();
testActualValueExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(apiExceptionVarExpr)
.setMethodName("getStatusCode")
.build();
testActualValueExpr =
MethodInvocationExpr.builder()
.setExprReferenceExpr(testActualValueExpr)
.setMethodName("getCode")
.build();
catchBodyExprs.add(
MethodInvocationExpr.builder()
.setStaticReferenceType(STATIC_TYPES.get("Assert"))
.setMethodName("assertEquals")
.setArguments(testExpectedValueExpr, testActualValueExpr)
.build());

return catchBodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList());
}

/* =========================================
* Type creator methods.
* =========================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public abstract class Field {

public abstract boolean isMap();

public abstract boolean isContainedInOneof();

@Nullable
public abstract ResourceReference resourceReference();

Expand All @@ -51,7 +53,8 @@ public static Builder builder() {
.setIsMessage(false)
.setIsEnum(false)
.setIsRepeated(false)
.setIsMap(false);
.setIsMap(false)
.setIsContainedInOneof(false);
}

@AutoValue.Builder
Expand All @@ -68,6 +71,8 @@ public abstract static class Builder {

public abstract Builder setIsMap(boolean isMap);

public abstract Builder setIsContainedInOneof(boolean isContainedInOneof);

public abstract Builder setResourceReference(ResourceReference resourceReference);

public abstract Builder setDescription(String description);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ private static Field parseField(FieldDescriptor fieldDescriptor, Descriptor mess
.setType(TypeParser.parseType(fieldDescriptor))
.setIsMessage(fieldDescriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE)
.setIsEnum(fieldDescriptor.getJavaType() == FieldDescriptor.JavaType.ENUM)
.setIsContainedInOneof(fieldDescriptor.getContainingOneof() != null)
.setIsRepeated(fieldDescriptor.isRepeated())
.setIsMap(fieldDescriptor.isMapField())
.setResourceReference(resourceReference)
Expand Down
Loading

0 comments on commit a0d4de5

Please sign in to comment.