| // Copyright 2020 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.skyframe; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static com.google.devtools.build.skyframe.WalkableGraphUtils.exists; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.Iterables; | |
| import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; | |
| import com.google.devtools.build.lib.cmdline.TargetPattern; | |
| import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternValue.PrepareDepsOfPatternSkyKeysAndExceptions; | |
| 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.build.skyframe.WalkableGraph; | |
| import java.io.IOException; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| /** Tests for {@link PrepareDepsOfTargetsUnderDirectoryFunction}. */ | |
| @RunWith(JUnit4.class) | |
| public final class PrepareDepsOfPatternFunctionTest extends BuildViewTestCase { | |
| private static PrepareDepsOfPatternSkyKeysAndExceptions createPrepDepsKeysMaybe( | |
| ImmutableList<String> patterns) { | |
| return PrepareDepsOfPatternValue.keys(patterns, TargetPattern.defaultParser()); | |
| } | |
| private static SkyKey createPrepDepsKey(String pattern) { | |
| PrepareDepsOfPatternSkyKeysAndExceptions keysAndExceptions = | |
| PrepareDepsOfPatternValue.keys(ImmutableList.of(pattern), TargetPattern.defaultParser()); | |
| assertThat(keysAndExceptions.getExceptions()).isEmpty(); | |
| return Iterables.getOnlyElement(keysAndExceptions.getValues()).getSkyKey(); | |
| } | |
| private EvaluationResult<PrepareDepsOfPatternValue> getEvaluationResult(SkyKey key) | |
| throws InterruptedException { | |
| EvaluationContext evaluationContext = | |
| EvaluationContext.newBuilder() | |
| .setKeepGoing(false) | |
| .setParallelism(SequencedSkyframeExecutor.DEFAULT_THREAD_COUNT) | |
| .setEventHandler(reporter) | |
| .build(); | |
| EvaluationResult<PrepareDepsOfPatternValue> evaluationResult = | |
| skyframeExecutor.getEvaluator().evaluate(ImmutableList.of(key), evaluationContext); | |
| Preconditions.checkState(!evaluationResult.hasError()); | |
| return evaluationResult; | |
| } | |
| @Test | |
| public void testUnparsablePattern() { | |
| // Given an string that can't be parsed, | |
| String unparsablePattern = "Not a//parsable/.../pattern/..//"; | |
| ImmutableList<String> unparsablePatternList = ImmutableList.of(unparsablePattern); | |
| // When PrepareDepsOfPatternValue.keys is called with that string as an argument, | |
| PrepareDepsOfPatternSkyKeysAndExceptions keysAndExceptionsResult = | |
| createPrepDepsKeysMaybe(unparsablePatternList); | |
| // Then it returns a wrapped TargetParsingException. | |
| assertThat(keysAndExceptionsResult.getValues()).isEmpty(); | |
| assertThat( | |
| Iterables.getOnlyElement(keysAndExceptionsResult.getExceptions()).getOriginalPattern()) | |
| .isEqualTo(unparsablePattern); | |
| } | |
| @Test | |
| public void testSingleTargetPatternEvaluationAndTransitiveLoading() throws Exception { | |
| evaluatePatternAndCheckTransitiveLoading("//a", /*adExists=*/ false); | |
| } | |
| @Test | |
| public void testTargetsBelowDirectoryPatternEvaluationAndTransitiveLoading() throws Exception { | |
| evaluatePatternAndCheckTransitiveLoading("//a/...", /*adExists=*/ true); | |
| } | |
| private void evaluatePatternAndCheckTransitiveLoading(String pattern, boolean adExists) | |
| throws IOException, InterruptedException, LabelSyntaxException { | |
| // Given a package "a" with a genrule "a" that depends on a target "b.txt" in a created | |
| // package "b", and a package "c" with a genrule "c", and a package "a/d" with a genrule "d". | |
| createPackages(); | |
| // When PrepareDepsOfPatternFunction is evaluated for the provided pattern, | |
| SkyKey key = createPrepDepsKey(pattern); | |
| EvaluationResult<PrepareDepsOfPatternValue> evaluationResult = getEvaluationResult(key); | |
| WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph()); | |
| // Then the result is not null, | |
| Preconditions.checkNotNull(evaluationResult.get(key)); | |
| // And the TransitiveTraversalValue for "a:a" is evaluated, | |
| SkyKey aaKey = TransitiveTraversalValue.key(Label.parseCanonical("@//a:a")); | |
| assertThat(exists(aaKey, graph)).isTrue(); | |
| // And that TransitiveTraversalValue depends on "b:b.txt". | |
| Iterable<SkyKey> depsOfAa = | |
| Iterables.getOnlyElement(graph.getDirectDeps(ImmutableList.of(aaKey)).values()); | |
| SkyKey bTxtKey = TransitiveTraversalValue.key(Label.parseCanonical("@//b:b.txt")); | |
| assertThat(depsOfAa).contains(bTxtKey); | |
| // And the TransitiveTraversalValue for "b:b.txt" is evaluated. | |
| assertThat(exists(bTxtKey, graph)).isTrue(); | |
| // And the TransitiveTraversalValue for "c:c" is NOT evaluated. | |
| SkyKey ccKey = TransitiveTraversalValue.key(Label.parseCanonical("@//c:c")); | |
| assertThat(exists(ccKey, graph)).isFalse(); | |
| // And the TransitiveTraversalValue for "a/d:d" is or is not evaluated depending on the provided | |
| // expectation. | |
| SkyKey adKey = TransitiveTraversalValue.key(Label.parseCanonical("@//a/d:d")); | |
| assertThat(exists(adKey, graph)).isEqualTo(adExists); | |
| } | |
| /** | |
| * Creates a package "a" with a genrule "a" that depends on a target "b.txt" in a created package | |
| * "b", and a package "c" with a genrule "c", and a package "a/d" with a genrule "d". | |
| */ | |
| private void createPackages() throws IOException { | |
| scratch.file("a/BUILD", "genrule(name='a', cmd='', srcs=['//b:b.txt'], outs=['a.out'])"); | |
| scratch.file("b/BUILD", "exports_files(['b.txt'])"); | |
| scratch.file("c/BUILD", "genrule(name='c', cmd='', srcs=['c.txt'], outs=['c.out'])"); | |
| scratch.file("a/d/BUILD", "genrule(name='d', cmd='', srcs=['d.txt'], outs=['d.out'])"); | |
| } | |
| } |