aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar Peter Schmitt <schmitt@google.com>2015-07-29 14:49:01 +0000
committerGravatar Lukacs Berki <lberki@google.com>2015-07-29 16:03:41 +0000
commit40deeff2fb1a0686be6276c1559ce051fe079a04 (patch)
treedb1ce933aeeecafb401be94741427552659254a7 /src/main
parenta0345bce94607a7096777d9013eed4c08cf12edc (diff)
Support coverage in experimental_ios_test.
Coverage depends on quite a few moving parts, several of which were changed for this test: - BuildConfiguration.getCoverageLabels() used to include gcov support, this is now replaced by the dedicated getGcovLabels() and a separate implicit attribute on TestBaseRule. This new attribute is then overridden in ExperimentalIosTest to use an xcode-compatible gcov. - Objc's TestSupport now correctly registers instrumented files and sets the necessary runfiles for collecting coverage. - ios_test's template exports gcda files for coverage computation after the test's execution. -- MOS_MIGRATED_REVID=99374435
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java20
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTest.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTestRule.java19
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java4
7 files changed, 134 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
index 4baf3b3d7e..48887ddf1b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -93,7 +93,17 @@ public class BaseRuleClasses {
@Override
public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
return configuration.isCodeCoverageEnabled()
- ? ImmutableList.<Label>copyOf(configuration.getCoverageLabels())
+ ? ImmutableList.copyOf(configuration.getCoverageLabels())
+ : ImmutableList.<Label>of();
+ }
+ };
+
+ private static final LateBoundLabelList<BuildConfiguration> GCOV =
+ new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+ @Override
+ public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.isCodeCoverageEnabled()
+ ? ImmutableList.copyOf(configuration.getGcovLabels())
: ImmutableList.<Label>of();
}
};
@@ -103,7 +113,7 @@ public class BaseRuleClasses {
@Override
public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
return configuration.isCodeCoverageEnabled()
- ? ImmutableList.<Label>copyOf(configuration.getCoverageReportGeneratorLabels())
+ ? ImmutableList.copyOf(configuration.getCoverageReportGeneratorLabels())
: ImmutableList.<Label>of();
}
};
@@ -158,6 +168,7 @@ public class BaseRuleClasses {
// implicitly depend on crosstool, which provides gcov. We could add gcov to
// InstrumentedFilesProvider.getInstrumentationMetadataFiles() (or a new method) for
// all the test rules that have C++ in their transitive closure. Then this could go.
+ .add(attr(":gcov", LABEL_LIST).cfg(HOST).value(GCOV))
.add(attr(":coverage_support", LABEL_LIST).cfg(HOST).value(COVERAGE_SUPPORT))
.add(attr(":coverage_report_generator", LABEL_LIST).cfg(HOST)
.value(COVERAGE_REPORT_GENERATOR))
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index f8b8199c16..d613f1e37e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -173,13 +173,20 @@ public final class BuildConfiguration {
}
/**
- * Returns all the coverage labels for the fragment.
+ * Returns the labels required to run coverage for the fragment.
*/
public ImmutableList<Label> getCoverageLabels() {
return ImmutableList.of();
}
/**
+ * Returns all labels required to run gcov, if provided by this fragment.
+ */
+ public ImmutableList<Label> getGcovLabels() {
+ return ImmutableList.of();
+ }
+
+ /**
* Returns the coverage report generator tool labels.
*/
public ImmutableList<Label> getCoverageReportGeneratorLabels() {
@@ -915,6 +922,7 @@ public final class BuildConfiguration {
private final ImmutableSet<Label> coverageLabels;
private final ImmutableSet<Label> coverageReportGeneratorLabels;
+ private final ImmutableSet<Label> gcovLabels;
// TODO(bazel-team): Move this to a configuration fragment.
private final PathFragment shExecutable;
@@ -1048,12 +1056,15 @@ public final class BuildConfiguration {
ImmutableSet.Builder<Label> coverageLabelsBuilder = ImmutableSet.builder();
ImmutableSet.Builder<Label> coverageReportGeneratorLabelsBuilder = ImmutableSet.builder();
+ ImmutableSet.Builder<Label> gcovLabelsBuilder = ImmutableSet.builder();
for (Fragment fragment : fragments.values()) {
coverageLabelsBuilder.addAll(fragment.getCoverageLabels());
coverageReportGeneratorLabelsBuilder.addAll(fragment.getCoverageReportGeneratorLabels());
+ gcovLabelsBuilder.addAll(fragment.getGcovLabels());
}
this.coverageLabels = coverageLabelsBuilder.build();
this.coverageReportGeneratorLabels = coverageReportGeneratorLabelsBuilder.build();
+ this.gcovLabels = gcovLabelsBuilder.build();
this.defaultShellEnvironment = setupShellEnvironment();
@@ -1519,6 +1530,13 @@ public final class BuildConfiguration {
}
/**
+ * Returns the set of labels for gcov.
+ */
+ public Set<Label> getGcovLabels() {
+ return gcovLabels;
+ }
+
+ /**
* Returns the set of labels for the coverage report generator.
*/
public Set<Label> getCoverageReportGeneratorLabels() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 06c9e6b9cc..a32c11697b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -1806,7 +1806,7 @@ public class CppConfiguration extends BuildConfiguration.Fragment {
}
@Override
- public ImmutableList<Label> getCoverageLabels() {
+ public ImmutableList<Label> getGcovLabels() {
// TODO(bazel-team): Using a gcov-specific crosstool filegroup here could reduce the number of
// inputs significantly. We'd also need to add logic in tools/coverage/collect_coverage.sh to
// drop crosstool dependency if metadataFiles does not contain *.gcno artifacts.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTest.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTest.java
index 5bbd81f126..4147412439 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTest.java
@@ -40,14 +40,13 @@ public final class ExperimentalIosTest extends IosTest {
Runfiles.Builder runfilesBuilder = new Runfiles.Builder()
.addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);
- NestedSetBuilder<Artifact> filesToBuildBuilder = NestedSetBuilder.<Artifact>stableOrder();
- filesToBuildBuilder.addTransitive(filesToBuild);
+ NestedSetBuilder<Artifact> filesToBuildBuilder = NestedSetBuilder.<Artifact>stableOrder()
+ .addTransitive(filesToBuild);
- TestSupport testSupport =
- new TestSupport(ruleContext)
- .registerTestRunnerActions()
- .addRunfiles(runfilesBuilder)
- .addFilesToBuild(filesToBuildBuilder);
+ TestSupport testSupport = new TestSupport(ruleContext)
+ .registerTestRunnerActions()
+ .addRunfiles(runfilesBuilder, common.getObjcProvider())
+ .addFilesToBuild(filesToBuildBuilder);
Artifact executable = testSupport.generatedTestScript();
@@ -61,6 +60,7 @@ public final class ExperimentalIosTest extends IosTest {
.add(RunfilesProvider.class, RunfilesProvider.simple(runfiles))
.add(ExecutionInfoProvider.class,
new ExecutionInfoProvider(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "")))
+ .addProviders(testSupport.getExtraProviders(common.getObjcProvider()))
.setRunfilesSupport(runfilesSupport, executable)
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTestRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTestRule.java
index 2a866b720c..7bf6ec2993 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalIosTestRule.java
@@ -14,20 +14,28 @@
package com.google.devtools.build.lib.rules.objc;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.Type.LABEL;
import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.Constants;
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.util.FileType;
+import java.util.List;
+
/**
* Rule definition for {@code experimental_ios_test} rule in Bazel.
*
@@ -78,6 +86,17 @@ public final class ExperimentalIosTestRule implements RuleDefinition {
.add(attr("$test_template", LABEL)
.value(env.getLabel("//tools/objc:ios_test.sh.bazel_template")))
.add(attr("$test_runner", LABEL).value(env.getLabel("//tools/objc:testrunner")))
+ .override(attr(":gcov", LABEL_LIST).cfg(HOST)
+ .value(new LateBoundLabelList<BuildConfiguration>() {
+ @Override
+ public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+ if (!configuration.isCodeCoverageEnabled()) {
+ return ImmutableList.of();
+ }
+ return ImmutableList.of(
+ configuration.getFragment(ObjcConfiguration.class).getGcovLabel());
+ }
+ }))
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
index f1774e4bb0..5506115905 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
@@ -18,22 +18,28 @@ import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.Runfiles.Builder;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.rules.objc.ObjcProvider.Key;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesProviderImpl;
import com.google.devtools.build.lib.util.FileType;
import java.util.List;
+import java.util.Map;
import javax.annotation.Nullable;
@@ -184,8 +190,10 @@ class TestSupport {
/**
* Adds all files needed to run this test to the passed Runfiles builder.
+ *
+ * @param objcProvider common information about this rule's attributes and its dependencies
*/
- TestSupport addRunfiles(Runfiles.Builder runfilesBuilder) {
+ TestSupport addRunfiles(Builder runfilesBuilder, ObjcProvider objcProvider) {
runfilesBuilder
.addArtifact(testIpa())
.addArtifacts(xctestIpa().asSet())
@@ -199,10 +207,71 @@ class TestSupport {
} else {
runfilesBuilder.addTransitiveArtifacts(labDeviceRunfiles());
}
+
+ if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
+ runfilesBuilder
+ .addTransitiveArtifacts(objcProvider.get(ObjcProvider.SOURCE))
+ .addTransitiveArtifacts(gcnoFiles(objcProvider));
+ }
return this;
}
/**
+ * Returns any additional providers that need to be exported to the rule context to the passed
+ * builder.
+ *
+ * @param objcProvider common information about this rule's attributes and its dependencies
+ */
+ public Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>
+ getExtraProviders(ObjcProvider objcProvider) {
+ return ImmutableMap.<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>of(
+ InstrumentedFilesProvider.class,
+ new InstrumentedFilesProviderImpl(
+ instrumentedFiles(objcProvider), gcnoFiles(objcProvider), gcovEnv()));
+ }
+
+ /**
+ * Returns a map of extra environment variable names to their values used to point to gcov binary,
+ * which should be added to the test action environment, if coverage is enabled.
+ */
+ private Map<String, String> gcovEnv() {
+ if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
+ return ImmutableMap.of("COVERAGE_GCOV_PATH",
+ ruleContext.getHostPrerequisiteArtifact(":gcov").getExecPathString());
+ }
+ return ImmutableMap.of();
+ }
+
+ /**
+ * Returns all GCC coverage notes files available for computing coverage.
+ */
+ private NestedSet<Artifact> gcnoFiles(ObjcProvider objcProvider) {
+ return filesWithXcTestApp(ObjcProvider.GCNO, objcProvider);
+ }
+
+ /**
+ * Returns all source files from the test (and if present xctest app) which have been
+ * instrumented for code coverage.
+ */
+ private NestedSet<Artifact> instrumentedFiles(ObjcProvider objcProvider) {
+ return filesWithXcTestApp(ObjcProvider.INSTRUMENTED_SOURCE, objcProvider);
+ }
+
+ private NestedSet<Artifact> filesWithXcTestApp(Key<Artifact> key, ObjcProvider objcProvider) {
+ NestedSet<Artifact> underlying = objcProvider.get(key);
+ XcTestAppProvider provider = ruleContext.getPrerequisite(
+ IosTest.XCTEST_APP, Mode.TARGET, XcTestAppProvider.class);
+ if (provider == null) {
+ return underlying;
+ }
+
+ return NestedSetBuilder.<Artifact>stableOrder()
+ .addTransitive(underlying)
+ .addTransitive(provider.getObjcProvider().get(key))
+ .build();
+ }
+
+ /**
* Jar files for plugins to the test runner. May be empty.
*/
private NestedSet<Artifact> plugins() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
index f7393322f1..958e8b3779 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestActionBuilder.java
@@ -209,6 +209,10 @@ public final class TestActionBuilder {
ruleContext.getPrerequisites(":coverage_support", Mode.HOST)) {
inputsBuilder.addTransitive(dep.getProvider(FileProvider.class).getFilesToBuild());
}
+ for (TransitiveInfoCollection dep :
+ ruleContext.getPrerequisites(":gcov", Mode.HOST)) {
+ inputsBuilder.addTransitive(dep.getProvider(FileProvider.class).getFilesToBuild());
+ }
Artifact instrumentedFileManifest =
InstrumentedFileManifestAction.getInstrumentedFileManifest(ruleContext,
ImmutableList.copyOf(instrumentedFiles.getInstrumentedFiles()),