blob: 71e50a52556559b3b8e378301ff94a4cff499b77 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.lib.rules.test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
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.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.test.TestProvider;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.TestTargetUtils;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.util.Pair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Implementation for the "test_suite" rule.
*/
public class TestSuite implements RuleConfiguredTargetFactory {
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws InterruptedException, RuleErrorException, ActionConflictException {
checkTestsAndSuites(ruleContext, "tests");
if (ruleContext.hasErrors()) {
return null;
}
//
// CAUTION! Keep this logic consistent with lib.query2.TestsFunction!
//
List<String> tagsAttribute =
new ArrayList<>(ruleContext.attributes().get("tags", Type.STRING_LIST));
// TODO(ulfjack): This is inconsistent with the other places that do test_suite expansion.
tagsAttribute.remove("manual");
Pair<Collection<String>, Collection<String>> requiredExcluded =
TestTargetUtils.sortTagsBySense(tagsAttribute);
List<TransitiveInfoCollection> directTestsAndSuitesBuilder = new ArrayList<>();
// The set of implicit tests is determined in
// {@link com.google.devtools.build.lib.packages.Package}.
// Manual tests are already filtered out there. That is what $implicit_tests is about.
for (TransitiveInfoCollection dep :
Iterables.concat(
getPrerequisites(ruleContext, "tests"),
getPrerequisites(ruleContext, "$implicit_tests"))) {
if (dep.getProvider(TestProvider.class) != null) {
// getTestTags maps to Rule.getRuleTags.
List<String> tags = dep.getProvider(TestProvider.class).getTestTags();
if (!TestTargetUtils.testMatchesFilters(
tags, requiredExcluded.first, requiredExcluded.second)) {
// This test does not match our filter. Ignore it.
continue;
}
}
directTestsAndSuitesBuilder.add(dep);
}
Runfiles runfiles = new Runfiles.Builder(
ruleContext.getWorkspaceName(), ruleContext.getConfiguration().legacyExternalRunfiles())
.addTargets(directTestsAndSuitesBuilder, RunfilesProvider.DATA_RUNFILES)
.build();
return new RuleConfiguredTargetBuilder(ruleContext)
.add(RunfilesProvider.class,
RunfilesProvider.withData(Runfiles.EMPTY, runfiles))
.add(TransitiveTestsProvider.class, new TransitiveTestsProvider())
.build();
}
private Iterable<? extends TransitiveInfoCollection> getPrerequisites(
RuleContext ruleContext, String attributeName) {
if (ruleContext.attributes().has(attributeName, BuildType.LABEL_LIST)) {
return ruleContext.getPrerequisites(attributeName, Mode.TARGET);
} else {
return ImmutableList.<TransitiveInfoCollection>of();
}
}
private void checkTestsAndSuites(RuleContext ruleContext, String attributeName) {
if (!ruleContext.attributes().has(attributeName, BuildType.LABEL_LIST)) {
return;
}
for (TransitiveInfoCollection dep : ruleContext.getPrerequisites(attributeName, Mode.TARGET)) {
// TODO(bazel-team): Maybe convert the TransitiveTestsProvider into an inner interface.
TransitiveTestsProvider provider = dep.getProvider(TransitiveTestsProvider.class);
TestProvider testProvider = dep.getProvider(TestProvider.class);
if (provider == null && testProvider == null) {
ruleContext.attributeError(attributeName,
"expecting a test or a test_suite rule but '" + dep.getLabel() + "' is not one");
}
}
}
}