Skip to content

Commit 726c774

Browse files
author
Alex Davies-Moore
committed
Added an initial test case using plugin input
This commit adds the first unit test method that drives the test using a binary CodeGeneratorRequest protocol buffer - it simulates the plugin generation step in the same way as the protoc framework would call it. There are now updated instructions to run the fixture generator and updated documents too.
1 parent b510dd9 commit 726c774

8 files changed

Lines changed: 184 additions & 28 deletions

File tree

README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ The flit plugin accepts the following plugin parameters:
6868
|:--------------|:---------:|:------------------------------|:----------------------------------------------------------|
6969
| `target` | Y | `enum[server]` | The type of target to generate e.g. server, client etc |
7070
| `type` | Y | `enum[spring,undertow,boot]` | Type of target to generate |
71-
71+
| `context` | N | `string` | Base context for routing, default is `/twirp` |
7272

7373
# Development
7474

@@ -84,4 +84,29 @@ Remote debugging can be performed as follows:
8484
./haberdasher.proto
8585

8686
When running with the above options, the generator will enable a remote java debug session on port 5005. This is useful
87-
for debugging a full generation step.
87+
for debugging a full generation step.
88+
89+
## Test Fixture Generation
90+
91+
The test resources contains a fake plugin that simply dumps the binary request to a file called `file.bin`. This utility
92+
can be used to generate test fixtures which can be fed to tests to drive plugin generation, for example:
93+
94+
$ protoc \
95+
--plugin=${PWD}/protoc-gen-dump \
96+
--dump_out=target=server,type=undertow:../java \
97+
./helloworld.proto
98+
$ mv file.bin helloworld.bin
99+
100+
This can be run from the resources directory to generate a `CodeGeneratorRequest` protobuf file, which can then be read
101+
by tests:
102+
103+
PluginProtos.CodeGeneratorRequest request = null;
104+
try (InputStream is = this.getClass().getClassLoader().getResource("helloworld.bin").openStream()) {
105+
request = PluginProtos.CodeGeneratorRequest
106+
.newBuilder()
107+
.mergeFrom(is)
108+
.build();
109+
}
110+
111+
Plugin plugin = new Plugin(request);
112+
plugin.process();

plugin/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ dependencies {
4242

4343
compileOnly('org.projectlombok:lombok:+')
4444

45-
46-
testCompile group: 'junit', name: 'junit', version: '4.12'
45+
testCompile 'com.github.javaparser:javaparser-core:3.6.9'
46+
testCompile 'junit:junit:4.12'
4747
}
4848

4949
shadowJar.dependsOn build
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.flit.protoc.gen.server.undertow;
2+
3+
import com.google.protobuf.compiler.PluginProtos;
4+
5+
import java.io.InputStream;
6+
7+
public abstract class BaseGeneratorTest {
8+
9+
public PluginProtos.CodeGeneratorRequest load(String resource) throws Exception {
10+
try (InputStream is = this.getClass().getClassLoader().getResource(resource).openStream()) {
11+
return PluginProtos.CodeGeneratorRequest
12+
.newBuilder()
13+
.mergeFrom(is)
14+
.build();
15+
}
16+
}
17+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package com.flit.protoc.gen.server.undertow;
2+
3+
import com.flit.protoc.Plugin;
4+
import com.github.javaparser.JavaParser;
5+
import com.github.javaparser.ast.CompilationUnit;
6+
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
7+
import com.github.javaparser.ast.body.MethodDeclaration;
8+
import com.google.protobuf.compiler.PluginProtos;
9+
import org.junit.Test;
10+
11+
import java.util.Map;
12+
import java.util.function.Function;
13+
import java.util.stream.Collectors;
14+
15+
import static org.junit.Assert.assertEquals;
16+
import static org.junit.Assert.assertNotNull;
17+
import static org.junit.Assert.assertTrue;
18+
19+
public class UndertowGeneratorTest extends BaseGeneratorTest {
20+
21+
@Test
22+
public void test_Generate() throws Exception {
23+
PluginProtos.CodeGeneratorRequest request = load("helloworld.undertow.bin");
24+
25+
Plugin plugin = new Plugin(request);
26+
PluginProtos.CodeGeneratorResponse response = plugin.process();
27+
28+
assertNotNull(response);
29+
assertEquals(2, response.getFileCount());
30+
31+
Map<String, PluginProtos.CodeGeneratorResponse.File> files = response.getFileList().stream().collect(Collectors.toMap(
32+
PluginProtos.CodeGeneratorResponse.File::getName,
33+
Function.identity()
34+
));
35+
36+
assertTrue(files.containsKey("com/example/helloworld/RpcHelloWorldService.java"));
37+
assertTrue(files.containsKey("com/example/helloworld/RpcHelloWorldHandler.java"));
38+
39+
// ensure it's parseable java
40+
test_Service(files.get("com/example/helloworld/RpcHelloWorldService.java"));
41+
test_Handler(files.get("com/example/helloworld/RpcHelloWorldHandler.java"));
42+
}
43+
44+
private void test_Handler(PluginProtos.CodeGeneratorResponse.File file) throws Exception {
45+
CompilationUnit cu = JavaParser.parse(file.getContent());
46+
cu.getPackageDeclaration().get().getName().asString();
47+
assertEquals("com.example.helloworld", cu.getPackageDeclaration().get().getName().asString());
48+
assertEquals(1, cu.getTypes().size());
49+
50+
assertTrue(cu.getType(0).isPublic());
51+
assertEquals("RpcHelloWorldHandler", cu.getType(0).getNameAsString());
52+
assertEquals("HttpHandler", ((ClassOrInterfaceDeclaration)cu.getType(0)).getImplementedTypes(0).getNameAsString());
53+
54+
Map<String, MethodDeclaration> methods = cu
55+
.findAll(MethodDeclaration.class)
56+
.stream()
57+
.collect(Collectors.toMap(MethodDeclaration::getNameAsString, Function.identity()));
58+
59+
assertEquals(3, methods.size());
60+
assertTrue(methods.containsKey("handleRequest"));
61+
assertTrue(methods.containsKey("handleHello"));
62+
assertTrue(methods.containsKey("handleHelloAgain"));
63+
64+
MethodDeclaration handleRequest = methods.get("handleRequest");
65+
assertEquals(1, handleRequest.getParameters().size());
66+
67+
assertEquals("HttpServerExchange", handleRequest.getParameterByName("exchange").get().getTypeAsString());
68+
assertEquals("void", handleRequest.getTypeAsString());
69+
assertEquals("Exception", handleRequest.getThrownException(0).asString());
70+
71+
MethodDeclaration handleHello = methods.get("handleHello");
72+
assertEquals(1, handleHello.getParameters().size());
73+
74+
assertEquals("HttpServerExchange", handleHello.getParameterByName("exchange").get().getTypeAsString());
75+
assertEquals("void", handleHello.getTypeAsString());
76+
assertEquals("Exception", handleHello.getThrownException(0).asString());
77+
78+
79+
MethodDeclaration handleHelloAgain = methods.get("handleHelloAgain");
80+
assertEquals(1, handleHelloAgain.getParameters().size());
81+
82+
assertEquals("HttpServerExchange", handleHelloAgain.getParameterByName("exchange").get().getTypeAsString());
83+
assertEquals("void", handleHelloAgain.getTypeAsString());
84+
assertEquals("Exception", handleHelloAgain.getThrownException(0).asString());
85+
86+
}
87+
88+
private void test_Service(PluginProtos.CodeGeneratorResponse.File file) throws Exception {
89+
CompilationUnit cu = JavaParser.parse(file.getContent());
90+
cu.getPackageDeclaration().get().getName().asString();
91+
assertEquals("com.example.helloworld", cu.getPackageDeclaration().get().getName().asString());
92+
assertEquals(1, cu.getTypes().size());
93+
94+
assertTrue(cu.getType(0).isPublic());
95+
assertEquals("RpcHelloWorldService", cu.getType(0).getNameAsString());
96+
97+
Map<String, MethodDeclaration> methods = cu
98+
.findAll(MethodDeclaration.class)
99+
.stream()
100+
.collect(Collectors.toMap(MethodDeclaration::getNameAsString, Function.identity()));
101+
102+
assertEquals(2, methods.size());
103+
assertTrue(methods.containsKey("handleHello"));
104+
assertTrue(methods.containsKey("handleHelloAgain"));
105+
106+
MethodDeclaration handleHello = methods.get("handleHello");
107+
assertEquals(1, handleHello.getParameters().size());
108+
109+
assertEquals("Helloworld.HelloReq", handleHello.getParameterByName("in").get().getTypeAsString());
110+
assertEquals("Helloworld.HelloResp", handleHello.getTypeAsString());
111+
112+
MethodDeclaration handleHelloAgain = methods.get("handleHelloAgain");
113+
assertEquals(1, handleHelloAgain.getParameters().size());
114+
115+
assertEquals("Helloworld.HelloReq", handleHelloAgain.getParameterByName("in").get().getTypeAsString());
116+
assertEquals("Helloworld.HelloResp", handleHelloAgain.getTypeAsString());
117+
}
118+
119+
}

plugin/src/test/java/tests.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

plugin/src/test/resources/helloworld.proto

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,4 @@ message HelloReq {
1313

1414
message HelloResp {
1515
string text = 1;
16-
}
17-
18-
service Status {
19-
rpc Status (Empty) returns (StatusResp);
20-
}
21-
22-
message Empty {
23-
}
24-
message StatusResp {
25-
}
26-
27-
28-
service Update {
29-
rpc Update (UpdateReq) returns (UpdateResp);
30-
}
31-
32-
message UpdateReq {
33-
}
34-
message UpdateResp {
35-
}
36-
37-
16+
}
818 Bytes
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
# ----------------------------------------------------------------------------------------------------------------------
4+
# Testing utility to dump a serialised CodeGeneratorRequest object which can then be fed into plugin tests to drive
5+
# generation.
6+
#
7+
# Example Usage:
8+
# protoc \
9+
# --plugin=${PWD}/protoc-gen-dump \
10+
# --dump_out=target=server,type=undertow:../java \
11+
# ./helloworld.proto
12+
#
13+
# In the above example, we need to pass in arguments to the dump plugin - different types can be used to test different
14+
# flows in the plugin generator resolution as well as asserting errors for incorrect/missing params.
15+
#
16+
# After generation, rename the file to something useful and then import in tests.
17+
# ----------------------------------------------------------------------------------------------------------------------
18+
cat >| file.bin

0 commit comments

Comments
 (0)