Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ggj][codegen][test] feat: add rpcExceptionTest for RPCs w/o overloads, support LRO #349

Merged
merged 9 commits into from
Sep 26, 2020
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