diff options
author | Damien Martin-Guillerez <dmarting@google.com> | 2016-01-13 09:39:16 +0000 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2016-01-13 13:19:15 +0000 |
commit | 0e396b827bca5ee507aadc875169e47d959a7136 (patch) | |
tree | e79d73a63c2148ca122af209f224ef1152e3ced8 /src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java | |
parent | 45fdee15c5d276462f4cb86d402551f02ac8bb0b (diff) |
Use our java test runner in Bazel
RELNOTES[NEW]: A new java test runner that support XML output and test filtering is supported.
It can be used by specifying --nolegacy_bazel_java_test or by speicifying the test_class
attribute on a java_test.
--
MOS_MIGRATED_REVID=112028955
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java | 162 |
1 files changed, 143 insertions, 19 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java index 182c2130f5..f55c0d939f 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java @@ -16,11 +16,14 @@ package com.google.devtools.build.lib.bazel.rules.java; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; +import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; @@ -38,6 +41,7 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationHelper; import com.google.devtools.build.lib.rules.java.JavaConfiguration; import com.google.devtools.build.lib.rules.java.JavaHelper; import com.google.devtools.build.lib.rules.java.JavaPrimaryClassProvider; +import com.google.devtools.build.lib.rules.java.JavaRunfilesProvider; import com.google.devtools.build.lib.rules.java.JavaSemantics; import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; import com.google.devtools.build.lib.rules.java.JavaUtil; @@ -51,6 +55,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; /** * Semantics for Bazel Java rules @@ -80,14 +85,29 @@ public class BazelJavaSemantics implements JavaSemantics { } } - private String getMainClassInternal(RuleContext ruleContext) { - return ruleContext.getRule().isAttrDefined("main_class", Type.STRING) + private String getMainClassInternal(RuleContext ruleContext, JavaCommon javaCommon) { + String mainClass = ruleContext.getRule().isAttrDefined("main_class", Type.STRING) ? ruleContext.attributes().get("main_class", Type.STRING) : ""; + boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); + boolean useTestrunner = ruleContext.attributes().get("use_testrunner", Type.BOOLEAN) + && !useLegacyJavaTest(ruleContext); + + if (createExecutable) { + if (useTestrunner) { + mainClass = "com.google.testing.junit.runner.BazelTestRunner"; + } else { /* java_binary or non-Junit java_test */ + if (mainClass.isEmpty()) { + mainClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts()); + } + } + } + + return mainClass; } private void checkMainClass(RuleContext ruleContext, JavaCommon javaCommon) { boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - String mainClass = getMainClassInternal(ruleContext); + String mainClass = getMainClassInternal(ruleContext, javaCommon); if (!createExecutable && !mainClass.isEmpty()) { ruleContext.ruleError("main class must not be specified when executable is not created"); @@ -95,8 +115,7 @@ public class BazelJavaSemantics implements JavaSemantics { if (createExecutable && mainClass.isEmpty()) { if (javaCommon.getSrcsArtifacts().isEmpty()) { - ruleContext.ruleError( - "need at least one of 'main_class', 'use_testrunner' or Java source files"); + ruleContext.ruleError("need at least one of 'main_class' or Java source files"); } mainClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts()); if (mainClass == null) { @@ -111,7 +130,7 @@ public class BazelJavaSemantics implements JavaSemantics { @Override public String getMainClass(RuleContext ruleContext, JavaCommon javaCommon) { checkMainClass(ruleContext, javaCommon); - return getMainClassInternal(ruleContext); + return getMainClassInternal(ruleContext, javaCommon); } @Override @@ -198,9 +217,30 @@ public class BazelJavaSemantics implements JavaSemantics { } } + private TransitiveInfoCollection getTestSupport(RuleContext ruleContext) { + if (!isJavaBinaryOrJavaTest(ruleContext)) { + return null; + } + if (useLegacyJavaTest(ruleContext)) { + return null; + } + + boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); + if (createExecutable && ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) { + return Iterables.getOnlyElement(ruleContext.getPrerequisites("$testsupport", Mode.TARGET)); + } else { + return null; + } + } + @Override public void addRunfilesForBinary(RuleContext ruleContext, Artifact launcher, Runfiles.Builder runfilesBuilder) { + TransitiveInfoCollection testSupport = getTestSupport(ruleContext); + if (testSupport != null) { + runfilesBuilder.addTarget(testSupport, JavaRunfilesProvider.TO_RUNFILES); + runfilesBuilder.addTarget(testSupport, RunfilesProvider.DEFAULT_RUNFILES); + } } @Override @@ -210,6 +250,13 @@ public class BazelJavaSemantics implements JavaSemantics { @Override public void collectTargetsTreatedAsDeps( RuleContext ruleContext, ImmutableList.Builder<TransitiveInfoCollection> builder) { + TransitiveInfoCollection testSupport = getTestSupport(ruleContext); + if (testSupport != null) { + // TODO(bazel-team): The testsupport is used as the test framework + // and really only needs to be on the runtime, not compile-time + // classpath. + builder.add(testSupport); + } } @Override @@ -230,17 +277,87 @@ public class BazelJavaSemantics implements JavaSemantics { NestedSetBuilder<Artifact> filesBuilder, RuleConfiguredTargetBuilder ruleBuilder) { if (isJavaBinaryOrJavaTest(ruleContext)) { - boolean createExec = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - ruleBuilder.add(JavaPrimaryClassProvider.class, - new JavaPrimaryClassProvider(createExec ? getMainClassInternal(ruleContext) : null)); + ruleBuilder.add( + JavaPrimaryClassProvider.class, + new JavaPrimaryClassProvider(getPrimaryClass(ruleContext, javaCommon))); + } + } + + // TODO(dmarting): simplify that logic when we remove the legacy Bazel java_test behavior. + private String getPrimaryClassLegacy(RuleContext ruleContext, JavaCommon javaCommon) { + boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); + if (!createExecutable) { + return null; } + return getMainClassInternal(ruleContext, javaCommon); } + private String getPrimaryClassNew(RuleContext ruleContext, JavaCommon javaCommon) { + boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); + Set<Artifact> sourceFiles = ImmutableSet.copyOf(javaCommon.getSrcsArtifacts()); + + if (!createExecutable) { + return null; + } + + boolean useTestrunner = ruleContext.attributes().get("use_testrunner", Type.BOOLEAN); + + String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING) + ? ruleContext.attributes().get("test_class", Type.STRING) : ""; + + if (useTestrunner) { + if (testClass.isEmpty()) { + testClass = javaCommon.determinePrimaryClass(sourceFiles); + if (testClass == null) { + ruleContext.ruleError("cannot determine junit.framework.Test class " + + "(Found no source file '" + ruleContext.getTarget().getName() + + ".java' and package name doesn't include 'java' or 'javatests'. " + + "You might want to rename the rule or add a 'test_class' " + + "attribute.)"); + } + } + return testClass; + } else { + if (!testClass.isEmpty()) { + ruleContext.attributeError("test_class", "this attribute is only meaningful to " + + "BazelTestRunner, but you are not using it (use_testrunner = 0)"); + } + + return getMainClassInternal(ruleContext, javaCommon); + } + } + + private String getPrimaryClass(RuleContext ruleContext, JavaCommon javaCommon) { + return useLegacyJavaTest(ruleContext) ? getPrimaryClassLegacy(ruleContext, javaCommon) + : getPrimaryClassNew(ruleContext, javaCommon); + } @Override public Iterable<String> getJvmFlags( RuleContext ruleContext, JavaCommon javaCommon, List<String> userJvmFlags) { - return userJvmFlags; + ImmutableList.Builder<String> jvmFlags = ImmutableList.builder(); + jvmFlags.addAll(userJvmFlags); + + if (!useLegacyJavaTest(ruleContext)) { + if (ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) { + String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING) + ? ruleContext.attributes().get("test_class", Type.STRING) : ""; + if (testClass.isEmpty()) { + testClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts()); + } + + if (testClass == null) { + ruleContext.ruleError("cannot determine test class"); + } else { + // Always run junit tests with -ea (enable assertion) + jvmFlags.add("-ea"); + // "suite" is a misnomer. + jvmFlags.add("-Dbazel.test_suite=" + ShellEscaper.escapeString(testClass)); + } + } + } + + return jvmFlags.build(); } @Override @@ -309,22 +426,29 @@ public class BazelJavaSemantics implements JavaSemantics { @Override public List<String> getExtraArguments(RuleContext ruleContext, JavaCommon javaCommon) { if (ruleContext.getRule().getRuleClass().equals("java_test")) { - if (ruleContext.getConfiguration().getTestArguments().isEmpty() - && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) { - ImmutableList.Builder<String> builder = ImmutableList.builder(); - for (Artifact artifact : javaCommon.getSrcsArtifacts()) { - PathFragment path = artifact.getRootRelativePath(); - String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path)); - if (className != null) { - builder.add(className); + if (useLegacyJavaTest(ruleContext)) { + if (ruleContext.getConfiguration().getTestArguments().isEmpty() + && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) { + ImmutableList.Builder<String> builder = ImmutableList.builder(); + for (Artifact artifact : javaCommon.getSrcsArtifacts()) { + PathFragment path = artifact.getRootRelativePath(); + String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path)); + if (className != null) { + builder.add(className); + } } + return builder.build(); } - return builder.build(); } } return ImmutableList.<String>of(); } + private boolean useLegacyJavaTest(RuleContext ruleContext) { + return !ruleContext.attributes().isAttributeValueExplicitlySpecified("test_class") + && ruleContext.getFragment(JavaConfiguration.class).useLegacyBazelJavaTest(); + } + @Override public String getJavaBuilderMainClass() { return JAVABUILDER_CLASS_NAME; |