| // Copyright 2015 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.packages; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static org.mockito.Mockito.mock; | |
| import static org.mockito.Mockito.when; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.common.collect.Iterables; | |
| import com.google.common.collect.Sets; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.cmdline.ResolvedTargets; | |
| import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; | |
| import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase; | |
| import com.google.devtools.build.lib.pkgcache.LoadingOptions; | |
| import com.google.devtools.build.lib.pkgcache.TestFilter; | |
| import com.google.devtools.build.lib.skyframe.TestsForTargetPatternValue; | |
| import com.google.devtools.build.lib.util.Pair; | |
| import com.google.devtools.build.skyframe.EvaluationContext; | |
| import com.google.devtools.build.skyframe.EvaluationResult; | |
| import com.google.devtools.build.skyframe.SkyKey; | |
| import com.google.devtools.common.options.Options; | |
| import java.util.Collection; | |
| import java.util.EnumSet; | |
| import java.util.function.Predicate; | |
| import net.starlark.java.syntax.Location; | |
| import org.junit.Before; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| @RunWith(JUnit4.class) | |
| public final class TestTargetUtilsTest extends PackageLoadingTestCase { | |
| private Target test1; | |
| private Target test2; | |
| private Target test1b; | |
| private Target suite; | |
| @Before | |
| public void createTargets() throws Exception { | |
| scratch.file( | |
| "tests/BUILD", | |
| """ | |
| load('//test_defs:foo_binary.bzl', 'foo_binary') | |
| load('//test_defs:foo_test.bzl', 'foo_test') | |
| foo_test( | |
| name = "small_test_1", | |
| size = "small", | |
| srcs = ["small_test_1.sh"], | |
| data = [":xUnit"], | |
| tags = ["tag1"], | |
| ) | |
| foo_test( | |
| name = "small_test_2", | |
| size = "small", | |
| srcs = ["small_test_2.sh"], | |
| data = ["//testing/shbase:googletest.sh"], | |
| tags = ["tag2"], | |
| ) | |
| foo_test( | |
| name = "large_test_1", | |
| size = "large", | |
| srcs = ["large_test_1.sh"], | |
| data = [ | |
| ":xUnit", | |
| "//testing/shbase:googletest.sh", | |
| ], | |
| tags = ["tag1"], | |
| ) | |
| foo_binary( | |
| name = "notest", | |
| srcs = ["notest.sh"], | |
| ) | |
| filegroup(name = "xUnit") | |
| test_suite( | |
| name = "smallTests", | |
| tags = ["small"], | |
| ) | |
| """); | |
| test1 = getTarget("//tests:small_test_1"); | |
| test2 = getTarget("//tests:small_test_2"); | |
| test1b = getTarget("//tests:large_test_1"); | |
| suite = getTarget("//tests:smallTests"); | |
| } | |
| @Test | |
| public void testFilterBySize() { | |
| Predicate<Target> sizeFilter = | |
| TestFilter.testSizeFilter(EnumSet.of(TestSize.SMALL, TestSize.LARGE)); | |
| assertThat(sizeFilter.test(test1)).isTrue(); | |
| assertThat(sizeFilter.test(test2)).isTrue(); | |
| assertThat(sizeFilter.test(test1b)).isTrue(); | |
| sizeFilter = TestFilter.testSizeFilter(EnumSet.of(TestSize.SMALL)); | |
| assertThat(sizeFilter.test(test1)).isTrue(); | |
| assertThat(sizeFilter.test(test2)).isTrue(); | |
| assertThat(sizeFilter.test(test1b)).isFalse(); | |
| } | |
| @Test | |
| public void testFilterByLang() { | |
| LoadingOptions options = Options.getDefaults(LoadingOptions.class); | |
| options.setTestLangFilterList(ImmutableList.of("positive", "-negative")); | |
| options.setTestSizeFilterSet(ImmutableSet.of()); | |
| options.setTestTimeoutFilterSet(ImmutableSet.of()); | |
| options.setTestTagFilterList(ImmutableList.of()); | |
| TestFilter filter = TestFilter.forOptions(options); | |
| Package pkg = mock(Package.class); | |
| RuleClass ruleClass = mock(RuleClass.class); | |
| when(ruleClass.getDefaultImplicitOutputsFunction()) | |
| .thenReturn(SafeImplicitOutputsFunction.NONE); | |
| when(ruleClass.getAttributeProvider()).thenReturn(mock(AttributeProvider.class)); | |
| Rule mockRule = | |
| new Rule( | |
| pkg, | |
| Label.parseCanonicalUnchecked("//pkg:a"), | |
| ruleClass, | |
| Location.fromFile(""), | |
| /* interiorCallStack= */ null); | |
| when(ruleClass.getName()).thenReturn("positive_test"); | |
| assertThat(filter.apply(mockRule)).isTrue(); | |
| when(ruleClass.getName()).thenReturn("negative_test"); | |
| assertThat(filter.apply(mockRule)).isFalse(); | |
| } | |
| @Test | |
| public void testFilterByTimeout() throws Exception { | |
| scratch.file( | |
| "timeouts/BUILD", | |
| """ | |
| load('//test_defs:foo_test.bzl', 'foo_test') | |
| foo_test( | |
| name = "long_timeout", | |
| size = "small", | |
| timeout = "long", | |
| srcs = ["a.sh"], | |
| ) | |
| foo_test( | |
| name = "short_timeout", | |
| size = "small", | |
| srcs = ["b.sh"], | |
| ) | |
| foo_test( | |
| name = "moderate_timeout", | |
| size = "small", | |
| timeout = "moderate", | |
| srcs = ["c.sh"], | |
| ) | |
| """); | |
| Target longTest = getTarget("//timeouts:long_timeout"); | |
| Target shortTest = getTarget("//timeouts:short_timeout"); | |
| Target moderateTest = getTarget("//timeouts:moderate_timeout"); | |
| Predicate<Target> timeoutFilter = | |
| TestFilter.testTimeoutFilter(EnumSet.of(TestTimeout.SHORT, TestTimeout.LONG)); | |
| assertThat(timeoutFilter.test(longTest)).isTrue(); | |
| assertThat(timeoutFilter.test(shortTest)).isTrue(); | |
| assertThat(timeoutFilter.test(moderateTest)).isFalse(); | |
| } | |
| @Test | |
| public void testSkyframeExpandTestSuites() throws Exception { | |
| assertExpandedSuitesSkyframe(Sets.newHashSet(test1, test2), ImmutableSet.of(test1, test2)); | |
| assertExpandedSuitesSkyframe(Sets.newHashSet(test1, test2), ImmutableSet.of(suite)); | |
| assertExpandedSuitesSkyframe( | |
| Sets.newHashSet(test1, test2, test1b), ImmutableSet.of(test1, suite, test1b)); | |
| // The large test if returned as filtered from the test_suite rule, but should still be in the | |
| // result set as it's explicitly added. | |
| assertExpandedSuitesSkyframe( | |
| Sets.newHashSet(test1, test2, test1b), ImmutableSet.of(test1b, suite)); | |
| } | |
| @Test | |
| public void testSortTagsBySenseSeparatesTagsNaively() { | |
| // Contrived, but intentional. | |
| Pair<Collection<String>, Collection<String>> result = | |
| TestTargetUtils.sortTagsBySense( | |
| ImmutableList.of("tag1", "tag2", "tag3", "-tag1", "+tag2", "-tag3")); | |
| assertThat(result.first).containsExactly("tag1", "tag2", "tag3"); | |
| assertThat(result.second).containsExactly("tag1", "tag3"); | |
| } | |
| // Regression test for b/489243968. | |
| @Test | |
| public void testStarlarkRuleNamedTestSuite_notExpandedLikeTestSuite() throws Exception { | |
| scratch.file( | |
| "test/test_suite.bzl", | |
| """ | |
| # Custom Starlark rule whose name happens to be test_suite. | |
| test_suite = rule( | |
| implementation = lambda ctx: [], | |
| ) | |
| """); | |
| scratch.file( | |
| "test/BUILD", | |
| """ | |
| load("//test:test_suite.bzl", "test_suite") | |
| test_suite(name = "not_a_real_test_suite") | |
| """); | |
| Target target = getTarget("//test:not_a_real_test_suite"); | |
| assertExpandedSuitesSkyframe(ImmutableList.of(target), ImmutableList.of(target)); | |
| } | |
| private void assertExpandedSuitesSkyframe(Iterable<Target> expected, Collection<Target> suites) | |
| throws Exception { | |
| ImmutableSet<Label> expectedLabels = | |
| ImmutableSet.copyOf(Iterables.transform(expected, Target::getLabel)); | |
| ImmutableSet<Label> suiteLabels = | |
| ImmutableSet.copyOf(Iterables.transform(suites, Target::getLabel)); | |
| SkyKey key = TestsForTargetPatternValue.key(suiteLabels); | |
| EvaluationContext evaluationContext = | |
| EvaluationContext.newBuilder() | |
| .setKeepGoing(false) | |
| .setParallelism(1) | |
| .setEventHandler(reporter) | |
| .build(); | |
| EvaluationResult<TestsForTargetPatternValue> result = | |
| getSkyframeExecutor().getEvaluator().evaluate(ImmutableList.of(key), evaluationContext); | |
| ResolvedTargets<Label> actual = result.get(key).getLabels(); | |
| assertThat(actual.hasError()).isFalse(); | |
| assertThat(actual.getTargets()).containsExactlyElementsIn(expectedLabels); | |
| } | |
| } |