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][infra][3/5] feat: implement update golden bazel rules for dummy test #314

Merged
merged 45 commits into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
42db152
add fileDiffUtils
xiaozhenliu-gg5 Sep 9, 2020
7c4b6a7
add new dummy unit test
xiaozhenliu-gg5 Sep 9, 2020
f42d269
format
xiaozhenliu-gg5 Sep 9, 2020
7224b5a
add assertUtils
xiaozhenliu-gg5 Sep 10, 2020
62ddbe6
format
xiaozhenliu-gg5 Sep 10, 2020
d9fbb0a
move dummy test to separate folder
xiaozhenliu-gg5 Sep 10, 2020
0e63a94
add compare strings method in diffUtils
xiaozhenliu-gg5 Sep 10, 2020
076ef47
format
xiaozhenliu-gg5 Sep 10, 2020
760b0a9
Merge branch 'dummy_test' of github.com:googleapis/gapic-generator-ja…
xiaozhenliu-gg5 Sep 10, 2020
25ce9ec
dummy test pass
xiaozhenliu-gg5 Sep 10, 2020
6f54239
reformat
xiaozhenliu-gg5 Sep 10, 2020
cf90743
merge
xiaozhenliu-gg5 Sep 10, 2020
e3563b9
add simple strings comparison
xiaozhenliu-gg5 Sep 10, 2020
2ff169e
add java_diff_test bzl
xiaozhenliu-gg5 Sep 11, 2020
7cc8219
group test framework helpers together
xiaozhenliu-gg5 Sep 11, 2020
ec51871
Merge branch 'java_diff_util' of github.com:googleapis/gapic-generato…
xiaozhenliu-gg5 Sep 11, 2020
2fce32e
run testRunner
xiaozhenliu-gg5 Sep 12, 2020
306eb83
format
xiaozhenliu-gg5 Sep 12, 2020
53da6c4
run single JUnit test and save output
xiaozhenliu-gg5 Sep 13, 2020
509746b
add copy of golden
xiaozhenliu-gg5 Sep 15, 2020
20b3b1f
format
xiaozhenliu-gg5 Sep 15, 2020
3af8ba7
working pipeline
xiaozhenliu-gg5 Sep 16, 2020
9e438ad
format
xiaozhenliu-gg5 Sep 16, 2020
4c542c7
clean up
xiaozhenliu-gg5 Sep 16, 2020
6e08814
get codegen in local_tmp
xiaozhenliu-gg5 Sep 17, 2020
f6de85e
format
xiaozhenliu-gg5 Sep 17, 2020
b04ea6b
add golden path to bazel rules
xiaozhenliu-gg5 Sep 17, 2020
15e26e3
working pipeline
xiaozhenliu-gg5 Sep 17, 2020
eb2f931
format
xiaozhenliu-gg5 Sep 17, 2020
278ade1
work!
xiaozhenliu-gg5 Sep 18, 2020
5c1a1fc
merge master
xiaozhenliu-gg5 Sep 18, 2020
ff4c2ac
clean up
xiaozhenliu-gg5 Sep 18, 2020
aeac134
fix
xiaozhenliu-gg5 Sep 18, 2020
f5f9ba9
feedback
xiaozhenliu-gg5 Sep 19, 2020
19d791c
clean
xiaozhenliu-gg5 Sep 19, 2020
5ccd3ea
comment
xiaozhenliu-gg5 Sep 19, 2020
a51f0ce
bazel rules feedbacj
xiaozhenliu-gg5 Sep 22, 2020
f230b09
java code feedback
xiaozhenliu-gg5 Sep 22, 2020
b51775d
move dependency
xiaozhenliu-gg5 Sep 22, 2020
6f8d04b
clean up
xiaozhenliu-gg5 Sep 22, 2020
f18c8cc
merge master
xiaozhenliu-gg5 Sep 22, 2020
d364be4
comment
xiaozhenliu-gg5 Sep 22, 2020
c681dc1
move hamcrest dep back
xiaozhenliu-gg5 Sep 23, 2020
1dc6ff3
Merge branch 'master' of github.com:googleapis/gapic-generator-java i…
xiaozhenliu-gg5 Sep 23, 2020
f91ee2c
add helpers in Utils
xiaozhenliu-gg5 Sep 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,28 @@ java_binary(
],
)

# JUnit runner binary, this is used to generate test output for updating goldens files.
# Run `bazel run testTarget_update` will trigger this runner.
java_binary(
name = "junit_runner",
srcs = [
"//src/test/java/com/google/api/generator/gapic/dummy:dummy_files",
"//src/test/java/com/google/api/generator/test/framework:framework_files",
],
data = ["//src/test/java/com/google/api/generator/gapic/dummy/goldens:goldens_files"],
jvm_flags = ["-Xmx512m"],
main_class = "com.google.api.generator.test.framework.SingleJUnitTestRunner",
visibility = ["//visibility:public"],
deps = [
"//src/main/java/com/google/api/generator/engine/ast",
"//src/main/java/com/google/api/generator/engine/writer",
"//src/test/java/com/google/api/generator/test/framework",
"@io_github_java_diff_utils//jar",
"@junit_junit//jar",
"@org_hamcrest_hamcrest_core//jar",
],
)

# google-java-format
java_binary(
name = "google_java_format_binary",
Expand Down
3 changes: 3 additions & 0 deletions dependencies.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ maven.org_threeten_threetenbp=org.threeten:threetenbp:1.3.3

# Testing.
maven.junit_junit=junit:junit:4.13
# This hamcrest-core dependency is for running JUnit test manually, before JUnit 4.11 it's wrapped along with JUnit package.
# But now it has to be explicitly added.
maven.org_hamcrest_hamcrest_core=org.hamcrest:hamcrest-core:1.3
miraleung marked this conversation as resolved.
Show resolved Hide resolved
maven.org_mockito_mockito_core=org.mockito:mockito-core:2.21.0
# Keep in sync with gax-java.
maven.com_google_truth_truth=com.google.truth:truth:1.0
87 changes: 87 additions & 0 deletions rules_bazel/java/java_diff_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
def _junit_output_impl(ctx):
test_class_name = ctx.attr.test_class_name
inputs = ctx.files.srcs
output = ctx.outputs.output
test_runner = ctx.executable.test_runner

command = """
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
mkdir local_tmp
TEST_OUTPUT_HOME="$(pwd)/local_tmp" \
{test_runner_path} $@
cd local_tmp
# Zip all files under local_tmp with all nested parent folders except for local_tmp itself.
# Zip files because there are cases that one Junit test can produce multiple goldens.
zip -r ../{output} .
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
miraleung marked this conversation as resolved.
Show resolved Hide resolved
""".format(
test_runner_path = test_runner.path,
output=output.path,
)

ctx.actions.run_shell(
inputs = inputs,
outputs = [output],
arguments = [test_class_name],
tools = [test_runner],
command = command,
)

junit_output_zip = rule(
attrs = {
"test_class_name": attr.string(mandatory=True),
"srcs": attr.label_list(
allow_files = True,
mandatory = True,
),
"test_runner": attr.label(
mandatory = True,
executable = True,
cfg = "host",
),
},
outputs = {
"output": "%{name}%.zip",
},
implementation = _junit_output_impl,
)

def _overwritten_golden_impl(ctx):
script_content = """
#!/bin/bash
cd ${{BUILD_WORKSPACE_DIRECTORY}}
unzip -ao {unit_test_results} -d src/test/java
""".format(
unit_test_results = ctx.file.unit_test_results.path,
)
ctx.actions.write(
output = ctx.outputs.bin,
content = script_content,
is_executable = True,
)
return [DefaultInfo(executable = ctx.outputs.bin)]


overwritten_golden = rule(
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
attrs = {
"unit_test_results": attr.label(
mandatory = True,
allow_single_file = True),
},
outputs = {
"bin": "%{name}.sh",
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
},
executable = True,
implementation = _overwritten_golden_impl,
)

def updated_golden(name, test_class_name, srcs):
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
junit_output_name = "%s_output" % name
junit_output_zip(
name = junit_output_name,
test_class_name = test_class_name,
test_runner = "//:junit_runner",
srcs = srcs,
)
overwritten_golden(
name = name,
unit_test_results = ":%s" % junit_output_name
)
18 changes: 17 additions & 1 deletion src/test/java/com/google/api/generator/gapic/dummy/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("//:rules_bazel/java/java_diff_test.bzl", "updated_golden")

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

TESTS = [
Expand All @@ -12,7 +14,7 @@ filegroup(
[java_test(
name = test_name,
srcs = ["{0}.java".format(test_name)],
data = ["//src/test/java/com/google/api/generator/gapic/dummy/goldens:goldens_files"],
data = glob(["goldens/*.golden"]),
test_class = "com.google.api.generator.gapic.dummy.{0}".format(test_name),
deps = [
"//src/main/java/com/google/api/generator/engine/ast",
Expand All @@ -21,3 +23,17 @@ filegroup(
"@junit_junit//jar",
],
) for test_name in TESTS]

TEST_CLASS_NAME = "com.google.api.generator.gapic.dummy.FileDiffInfraDummyTest"

# Run `bazel run src/test/java/com/google/api/generator/gapic/dummy:FileDiffInfraDummyTest_update`
# to update goldens as expected generated code.
updated_golden(
name = "FileDiffInfraDummyTest_update",
srcs = [
":dummy_files",
"//src/test/java/com/google/api/generator/gapic/dummy/goldens:goldens_files",
"//src/test/java/com/google/api/generator/test/framework:framework_files",
],
test_class_name = TEST_CLASS_NAME,
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.api.generator.engine.ast.ScopeNode;
import com.google.api.generator.engine.writer.JavaWriterVisitor;
import com.google.api.generator.test.framework.Assert;
import com.google.api.generator.test.framework.Utils;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
Expand All @@ -34,8 +35,11 @@ public class FileDiffInfraDummyTest {
// created.
//
// TODO(xiaozhenliu): remove this test class once the file-diff infra is in place and well-tested.
private static final String GOLDENFILES_DIRECTORY =
"src/test/java/com/google/api/generator/gapic/dummy/goldens/";
private final String GOLDENFILES_DIRECTORY = Utils.getGoldenDir(this.getClass());
private final String GOLDENFILES_SIMPLE_CLASS =
Utils.getClassName(this.getClass()) + "SimpleClass.golden";
private final String GOLDENFILES_CLASS_WITH_HEADER =
Utils.getClassName(this.getClass()) + "ClassWithHeader.golden";

@Test
public void simpleClass() {
Expand All @@ -51,8 +55,8 @@ public void simpleClass() {
.build();
JavaWriterVisitor visitor = new JavaWriterVisitor();
classDef.accept(visitor);
Path goldenFilePath =
Paths.get(GOLDENFILES_DIRECTORY, "FileDiffInfraDummyTestSimpleClass.golden");
Utils.saveCodegenToFile(this.getClass(), GOLDENFILES_SIMPLE_CLASS, visitor.write());
Path goldenFilePath = Paths.get(GOLDENFILES_DIRECTORY, GOLDENFILES_SIMPLE_CLASS);
Assert.assertCodeEquals(goldenFilePath, visitor.write());
}

Expand All @@ -69,8 +73,9 @@ public void classWithHeader() {
.build();
JavaWriterVisitor visitor = new JavaWriterVisitor();
classDef.accept(visitor);
Path goldenFilePath =
Paths.get(GOLDENFILES_DIRECTORY, "FileDiffInfraDummyTestClassWithHeader.golden");
// Save the generated code to a file for updating goldens if needed.
Utils.saveCodegenToFile(this.getClass(), GOLDENFILES_CLASS_WITH_HEADER, visitor.write());
Path goldenFilePath = Paths.get(GOLDENFILES_DIRECTORY, GOLDENFILES_CLASS_WITH_HEADER);
Assert.assertCodeEquals(goldenFilePath, visitor.write());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ java_library(
srcs = [
":framework_files",
],
data = ["//src/test/java/com/google/api/generator/gapic/dummy/goldens:goldens_files"],
deps = [
"@io_github_java_diff_utils//jar",
"@junit_junit//jar",
"@org_hamcrest_hamcrest_core//jar",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.generator.test.framework;

import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;

public class SingleJUnitTestRunner {
// SingleJUnitTestRunner runs single JUnit test whose class name is passed through `args`.
// This is used to prepare codegen for updating goldens files.
public static void main(String... args) {
// Check whether the test class name is passed correctly e.g.
// `com.google.api.generator.gapic.composer.ComposerTest`
if (args.length < 1) {
throw new MissingRequiredArgException("Missing the JUnit class name argument.");
}
String className = args[0];
Class clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new JUnitClassNotFoundException(
String.format("JUnit test class %s is not found.", className));
}
Result result = new JUnitCore().run(Request.aClass(clazz));
if (!result.wasSuccessful()) {
System.out.println("Tests have failures: " + result.getFailures());
}
}

public static class JUnitClassNotFoundException extends RuntimeException {
public JUnitClassNotFoundException(String errorMessage) {
super(errorMessage);
}

public JUnitClassNotFoundException(String errorMessage, Throwable cause) {
super(errorMessage, cause);
}
}

public static class MissingRequiredArgException extends RuntimeException {
public MissingRequiredArgException(String errorMessage) {
super(errorMessage);
}

public MissingRequiredArgException(String errorMessage, Throwable cause) {
super(errorMessage, cause);
}
}
}
75 changes: 75 additions & 0 deletions src/test/java/com/google/api/generator/test/framework/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.generator.test.framework;

import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Utils {
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
/**
* Save the generated code from JUnit test to a file for updating goldens. These files will be
* saved as a zip file, then unzipped to overwrite goldens files. The relative path
* `com/google/..` which is identical with the location of goldens files which will help us easily
* replace the original goldens. For example:
* `src/test/java/com/google/api/generator/gapic/composer/ComposerTest.java` will save the
* generated code into a file called `ComposerTest.golden` at
* `$TEST_OUTPUT_HOME/com/google/api/generator/gapic/composer/goldens/ComposerTest.golden`.
*
* @param clazz the test class.
* @param fileName the name of saved file, usually it is test method name with suffix `.golden`.
* @param codegen the generated code from JUnit test.
*/
public static void saveCodegenToFile(Class clazz, String fileName, String codegen) {
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
// This system environment variable `TEST_OUTPUT_HOME` is used to specify a folder
// which contains generated output from JUnit test.
// It will be set when running `bazel run testTarget_update` command.
String testOutputHome = System.getenv("TEST_OUTPUT_HOME");
String relativeGoldenDir = getTestoutGoldenDir(clazz);
Path testOutputDir = Paths.get(testOutputHome, relativeGoldenDir);
testOutputDir.toFile().mkdirs();
try (FileWriter myWriter =
new FileWriter(Paths.get(testOutputHome, relativeGoldenDir, fileName).toFile())) {
myWriter.write(codegen);
} catch (IOException e) {
throw new SaveCodegenToFileException(
miraleung marked this conversation as resolved.
Show resolved Hide resolved
String.format(
"Error occured when saving codegen to file %s/%s", relativeGoldenDir, fileName));
}
}

private static String getTestoutGoldenDir(Class clazz) {
return clazz.getPackage().getName().replace(".", "/") + "/goldens/";
}

public static String getGoldenDir(Class clazz) {
return "src/test/java/" + clazz.getPackage().getName().replace(".", "/") + "/goldens/";
}

public static String getClassName(Class clazz) {
return clazz.getSimpleName();
}

public static class SaveCodegenToFileException extends RuntimeException {
public SaveCodegenToFileException(String errorMessage) {
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
super(errorMessage);
}

public SaveCodegenToFileException(String errorMessage, Throwable cause) {
super(errorMessage, cause);
}
}
}