Skip to content

Commit

Permalink
fix: get data types from events.proto (#130)
Browse files Browse the repository at this point in the history
* fix: get data types from events.proto

* lint

* Update CONTRIBUTING.md
  • Loading branch information
averikitsch committed Jan 30, 2023
1 parent b4a9a2b commit 5800af4
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 592 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ Code in this repo is formatted with
[google-java-format](https://github.com/google/google-java-format).
To run formatting on your project, you can run:
```
mvn com.coveo:fmt-maven-plugin:format
```
mvn com.spotify.fmt:fmt-maven-plugin:format
```
2 changes: 1 addition & 1 deletion google-cloudevent-types/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>2.1.3</version>
<version>2.2.0</version>
</dependency>

<!-- Test dependencies -->
Expand Down
38 changes: 14 additions & 24 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,35 +86,25 @@
<module>protoc-gen-java-snowpea</module>
</modules>

<reporting>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.4.1</version>
<reportSets>
<reportSet>
<reports>
<report>index</report>
<report>dependency-info</report>
<report>team</report>
<report>ci-management</report>
<report>issue-management</report>
<report>licenses</report>
<report>scm</report>
<report>dependency-management</report>
<report>distribution-management</report>
<report>summary</report>
<report>modules</report>
</reports>
</reportSet>
</reportSets>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.2.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>10.6.0</version>
</dependency>
</dependencies>
<configuration>
<dependencyDetailsEnabled>true</dependencyDetailsEnabled>
<artifactId>${site.installationModule}</artifactId>
<packaging>jar</packaging>
<configLocation>google_checks.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
</configuration>
</plugin>
</plugins>
</reporting>
</build>
</project>
8 changes: 4 additions & 4 deletions protoc-gen-java-snowpea/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ This plugin generates tests for Google Event Types Library for Java to ensure th
## Things to Know

* This plugin generates a test file per "main" event type
* The "main" event type is determined by the protobuf's message "Data" suffix, i.e. generate "MessagePublishedData" and not "PubSubMessage"
* These main event types are found in `data.proto`
* Generate file name and path ensure the Java package and event type is used: `google/events/cloud/pubsub/v1/data.proto` is converted to `com/google/events/cloud/pubsub/v1/MessagePublishedDataTest.java`
* Main event types are determined by the data type of Event messages, i.e. "MessagePublishedEvent"
* These main event types are found in `events.proto`
* Generate file name and path ensure the Java package and event type is used: `google/events/cloud/pubsub/v1/events.proto` is converted to `com/google/events/cloud/pubsub/v1/MessagePublishedDataTest.java`

* The binary is defined by the [startup-script.sh](./startup-script.sh) to run the uber-jar
* It is designed to run from parent directory
Expand Down Expand Up @@ -88,5 +88,5 @@ protoc \
-I $GOOGLE_CLOUDEVENTS/proto \
-I $GOOGLE_CLOUDEVENTS/third_party \
--experimental_allow_proto3_optional \
$GOOGLE_CLOUDEVENTS/proto/google/events/cloud/pubsub/v1/data.proto
$GOOGLE_CLOUDEVENTS/proto/google/events/cloud/pubsub/v1/events.proto
```
6 changes: 6 additions & 0 deletions protoc-gen-java-snowpea/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
<version>1.1.3</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
109 changes: 56 additions & 53 deletions protoc-gen-java-snowpea/src/main/java/com/google/events/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
import static com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL;

import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest;
import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse;
import java.io.StringWriter;
import java.time.Year;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
Expand All @@ -42,66 +43,57 @@
public class Generator {
private static final Logger LOGGER = LoggerFactory.getLogger(Generator.class);

public static CodeGeneratorResponse generate(CodeGeneratorRequest request)
throws DescriptorValidationException {

public static CodeGeneratorResponse generate(CodeGeneratorRequest request) {
// CodeGeneratorRequest contain FileDescriptorProtos for all the proto
// files and associated dependencies. These FileDescriptorProtos will
// be converted into FileDescriptor instances and mapped to file names.
// files and associated dependencies.

// FileDescriptor describes a .proto file, including everything defined within.
// That includes descriptors for all the messages and file
// descriptors for all other imported .proto files (dependencies).
// https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.Descriptors.FileDescriptor
Map<String, Descriptors.FileDescriptor> filesByName = new HashMap<>();
// Initialize set for event types
Set<FieldDescriptorProto> set = new HashSet<FieldDescriptorProto>();
for (DescriptorProtos.FileDescriptorProto fp : request.getProtoFileList()) {
LOGGER.debug("Preprocessing FileDescriptorProto: " + fp.getName());
// fp.getDependencyList() gets names of files imported by this file.
// Look up each dependency in filesByName Map
Descriptors.FileDescriptor dependencies[] =
fp.getDependencyList().stream()
.map(filesByName::get)
.toArray(Descriptors.FileDescriptor[]::new);
String file = fp.getName();
LOGGER.info("Input Protobuf: " + file);
if (!file.endsWith("events.proto")) {
LOGGER.warn("Skipping... Expected file: events.proto.");
continue;
}

Descriptors.FileDescriptor fd = Descriptors.FileDescriptor.buildFrom(fp, dependencies);
filesByName.put(fp.getName(), fd);
// Filter message types for data fields
List<DescriptorProto> messageTypes = fp.getMessageTypeList();
messageTypes.stream()
.forEach(
message -> {
List<FieldDescriptorProto> fields =
message.getFieldList().stream()
.filter(field -> field.getName().equalsIgnoreCase("data"))
.collect(Collectors.toList());
set.addAll(fields);
});
}

// The plugin writes an encoded CodeGeneratorResponse to stdout.
CodeGeneratorResponse.Builder response =
CodeGeneratorResponse.newBuilder()
.setSupportedFeatures(FEATURE_PROTO3_OPTIONAL.getNumber());

// Process the .proto files that were explicitly listed on the command-line.
for (String fileName : request.getFileToGenerateList()) {
// Process only data.proto
// Ignore events.protos, cloudevent.protos, and named 3P protos
if (fileName.endsWith("data.proto")) {
Descriptors.FileDescriptor fd = filesByName.get(fileName);
for (Descriptors.Descriptor messageType : fd.getMessageTypes()) {
// Process Top Level Messages ie message types ending in "Data"
if (messageType.getName().endsWith("Data")) {
LOGGER.info("Generating Test File for " + messageType.getName());
// Generate file name and path
// google/events/cloud/pubsub/v1/data.proto -->
// com/google/events/cloud/pubsub/v1/MessagePublishedDataTest.java
String name =
"com/"
+ fd.getFullName()
.replaceAll("data.proto", messageType.getName() + "Test.java");
// Generate test file
String testFileContent = generateTestFile(fd, messageType, request.getParameter());
// Add test file to response
response.addFileBuilder().setName(name).setContent(testFileContent);
}
}
}
for (FieldDescriptorProto dataField : set) {
List<String> fieldPackage = getPackageName(dataField);
LOGGER.info("Generating Test File for " + fieldPackage.get(1));
// Generate file name and path
// com.google.events.cloud.pubsub.v1 -->
// com/google/events/cloud/pubsub/v1/MessagePublishedDataTest.java
String name =
fieldPackage.get(0).replaceAll("\\.", "\\/") + "/" + fieldPackage.get(1) + "Test.java";
LOGGER.info(name);
// Generate test file
String testFileContent = generateTestFile(dataField, request.getParameter());
// Add test file to response
response.addFileBuilder().setName(name).setContent(testFileContent);
}

return response.build();
}

private static String generateTestFile(
Descriptors.FileDescriptor fd, Descriptors.Descriptor messageType, String opts) {
private static String generateTestFile(FieldDescriptorProto dataField, String opts) {
// Instantiate Velocity Engine
VelocityEngine velocityEngine = new VelocityEngine();
// Set properties to locate template
Expand All @@ -110,11 +102,14 @@ private static String generateTestFile(
"resource.loader.classpath.class", ClasspathResourceLoader.class.getName());
velocityEngine.init();
Template t = velocityEngine.getTemplate("classTemplate.vm");

// Get template variable values
String packageName = fd.getPackage();
String className = messageType.getName();
String packageName = getPackageName(dataField).get(0);
String className = getPackageName(dataField).get(1);
List<String> optList = Arrays.asList(opts.split("\\s*,\\s*"));
Boolean skipStrict = optList.stream().filter(opt -> opt.contains(className)).collect(Collectors.toList()).size() > 0;
Boolean skipStrict =
optList.stream().filter(opt -> opt.contains(className)).collect(Collectors.toList()).size()
> 0;

// Add variables to template
VelocityContext context = new VelocityContext();
Expand All @@ -129,4 +124,12 @@ private static String generateTestFile(

return writer.toString();
}

private static List<String> getPackageName(FieldDescriptorProto dataField) {
List<String> typeName = new ArrayList<String>();
Collections.addAll(typeName, dataField.getTypeName().substring(1).split("\\."));
String className = typeName.remove(typeName.size() - 1);
String packageName = "com." + String.join(".", typeName);
return Arrays.asList(packageName, className);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.google.events;

import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest;
import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse;
import java.io.IOException;
Expand All @@ -26,11 +25,10 @@
public class Plugin {
private static final Logger LOGGER = LoggerFactory.getLogger(Plugin.class);

public static void main(String[] args) throws IOException, DescriptorValidationException {
public static void main(String[] args) throws IOException {
// An encoded CodeGeneratorRequest is written to the plugin's stdin
CodeGeneratorRequest request = CodeGeneratorRequest.parseFrom(System.in);
LOGGER.debug("Plugin opt: " + request.getParameter());

LOGGER.info("Plugin opt: " + request.getParameter());
// Generate test files from proto messages
CodeGeneratorResponse response = Generator.generate(request);
// Write to Plugin's stdout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// Code generated by protoc-gen-java-snowpea. DO NOT EDIT.

package com.${packageName};
package ${packageName};

import static org.junit.Assert.assertTrue;

Expand Down

0 comments on commit 5800af4

Please sign in to comment.