Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 1 | // Copyright 2015 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.skyframe; |
| 15 | |
| 16 | import static com.google.common.truth.Truth.assertThat; |
Janak Ramakrishnan | 112840b | 2016-12-29 21:49:56 +0000 | [diff] [blame] | 17 | import static com.google.devtools.build.skyframe.WalkableGraphUtils.exists; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 18 | |
tomlu | a155b53 | 2017-11-08 20:12:47 +0100 | [diff] [blame] | 19 | import com.google.common.base.Preconditions; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableList; |
| 21 | import com.google.common.collect.ImmutableSet; |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 22 | import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; |
Kristina Chodorow | a1a31ff | 2016-07-27 16:34:27 +0000 | [diff] [blame] | 23 | import com.google.devtools.build.lib.cmdline.RepositoryName; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.vfs.Path; |
| 25 | import com.google.devtools.build.lib.vfs.PathFragment; |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 26 | import com.google.devtools.build.lib.vfs.Root; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 27 | import com.google.devtools.build.lib.vfs.RootedPath; |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 28 | import com.google.devtools.build.skyframe.EvaluationContext; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 29 | import com.google.devtools.build.skyframe.EvaluationResult; |
| 30 | import com.google.devtools.build.skyframe.SkyKey; |
| 31 | import com.google.devtools.build.skyframe.WalkableGraph; |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 32 | import org.junit.Test; |
| 33 | import org.junit.runner.RunWith; |
| 34 | import org.junit.runners.JUnit4; |
| 35 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 36 | /** |
| 37 | * Tests for {@link RecursivePkgFunction}. Unfortunately, we can't directly test |
| 38 | * RecursivePkgFunction as it uses PackageValues, and PackageFunction uses legacy stuff that |
| 39 | * isn't easily mockable. So our testing strategy is to make hacky calls to |
| 40 | * SequencedSkyframeExecutor. |
| 41 | * |
| 42 | * <p>Target parsing tests already cover most of the behavior of RecursivePkgFunction, but there |
| 43 | * are a couple of corner cases we need to test directly. |
| 44 | */ |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 45 | @RunWith(JUnit4.class) |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 46 | public class RecursivePkgFunctionTest extends BuildViewTestCase { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 47 | |
ajurkowski | e298291 | 2020-04-09 10:32:08 -0700 | [diff] [blame] | 48 | private static SkyKey buildRecursivePkgKey( |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 49 | Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) { |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 50 | RootedPath rootedPath = RootedPath.toRootedPath(Root.fromPath(root), rootRelativePath); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 51 | return RecursivePkgValue.key( |
Kristina Chodorow | a1a31ff | 2016-07-27 16:34:27 +0000 | [diff] [blame] | 52 | RepositoryName.MAIN, rootedPath, excludedPaths); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | private RecursivePkgValue buildRecursivePkgValue(Path root, PathFragment rootRelativePath) |
| 56 | throws Exception { |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 57 | return buildRecursivePkgValue(root, rootRelativePath, ImmutableSet.of()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | private RecursivePkgValue buildRecursivePkgValue( |
| 61 | Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) |
| 62 | throws Exception { |
| 63 | SkyKey key = buildRecursivePkgKey(root, rootRelativePath, excludedPaths); |
| 64 | return getEvaluationResult(key).get(key); |
| 65 | } |
| 66 | |
| 67 | private EvaluationResult<RecursivePkgValue> getEvaluationResult(SkyKey key) |
| 68 | throws InterruptedException { |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 69 | EvaluationContext evaluationContext = |
| 70 | EvaluationContext.newBuilder() |
| 71 | .setKeepGoing(false) |
| 72 | .setNumThreads(SequencedSkyframeExecutor.DEFAULT_THREAD_COUNT) |
michajlo | 7a485be | 2020-07-30 11:08:46 -0700 | [diff] [blame] | 73 | .setEventHandler(reporter) |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 74 | .build(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 75 | EvaluationResult<RecursivePkgValue> evaluationResult = |
Googler | 0592f3f | 2019-07-12 09:00:46 -0700 | [diff] [blame] | 76 | skyframeExecutor.getDriver().evaluate(ImmutableList.of(key), evaluationContext); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 77 | Preconditions.checkState(!evaluationResult.hasError()); |
| 78 | return evaluationResult; |
| 79 | } |
| 80 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 81 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 82 | public void testStartingAtBuildFile() throws Exception { |
| 83 | scratch.file("a/b/c/BUILD"); |
| 84 | RecursivePkgValue value = |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 85 | buildRecursivePkgValue(rootDirectory, PathFragment.create("a/b/c/BUILD")); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 86 | assertThat(value.getPackages().isEmpty()).isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 87 | } |
| 88 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 89 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 90 | public void testPackagesUnderMultipleRoots() throws Exception { |
carmi | e3824d4 | 2018-04-03 14:58:26 -0700 | [diff] [blame] | 91 | // PackageLoader doesn't support --package_path. |
| 92 | initializeSkyframeExecutor(/*doPackageLoadingChecks=*/ false); |
| 93 | skyframeExecutor = getSkyframeExecutor(); |
| 94 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 95 | Path root1 = rootDirectory.getRelative("root1"); |
| 96 | Path root2 = rootDirectory.getRelative("root2"); |
| 97 | scratch.file(root1 + "/WORKSPACE"); |
| 98 | scratch.file(root2 + "/WORKSPACE"); |
| 99 | scratch.file(root1 + "/a/BUILD"); |
| 100 | scratch.file(root2 + "/a/b/BUILD"); |
ajurkowski | d74b0ec | 2020-04-13 10:58:21 -0700 | [diff] [blame] | 101 | setPackageOptions("--package_path=" + "root1" + ":" + "root2"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 102 | |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 103 | RecursivePkgValue valueForRoot1 = buildRecursivePkgValue(root1, PathFragment.create("a")); |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 104 | String root1Pkg = valueForRoot1.getPackages().getSingleton(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 105 | assertThat(root1Pkg).isEqualTo("a"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 106 | |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 107 | RecursivePkgValue valueForRoot2 = buildRecursivePkgValue(root2, PathFragment.create("a")); |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 108 | String root2Pkg = valueForRoot2.getPackages().getSingleton(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 109 | assertThat(root2Pkg).isEqualTo("a/b"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 110 | } |
| 111 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 112 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 113 | public void testSubdirectoryExclusion() throws Exception { |
| 114 | // Given a package "a" with two packages below it, "a/b" and "a/c", |
| 115 | scratch.file("a/BUILD"); |
| 116 | scratch.file("a/b/BUILD"); |
| 117 | scratch.file("a/c/BUILD"); |
| 118 | |
| 119 | // When the top package is evaluated for recursive package values, and "a/b" is excluded, |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 120 | PathFragment excludedPathFragment = PathFragment.create("a/b"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 121 | SkyKey key = |
| 122 | buildRecursivePkgKey( |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 123 | rootDirectory, PathFragment.create("a"), ImmutableSet.of(excludedPathFragment)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 124 | EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key); |
| 125 | RecursivePkgValue value = evaluationResult.get(key); |
| 126 | |
| 127 | // Then the package corresponding to "a/b" is not present in the result, |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 128 | assertThat(value.getPackages().toList()).doesNotContain("a/b"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 129 | |
| 130 | // And the "a" package and "a/c" package are. |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 131 | assertThat(value.getPackages().toList()).contains("a"); |
| 132 | assertThat(value.getPackages().toList()).contains("a/c"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 133 | |
| 134 | // Also, the computation graph does not contain a cached value for "a/b". |
| 135 | WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 136 | assertThat( |
| 137 | exists( |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 138 | buildRecursivePkgKey(rootDirectory, excludedPathFragment, ImmutableSet.of()), |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 139 | graph)) |
| 140 | .isFalse(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 141 | |
| 142 | // And the computation graph does contain a cached value for "a/c" with the empty set excluded, |
| 143 | // because that key was evaluated. |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 144 | assertThat( |
| 145 | exists( |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 146 | buildRecursivePkgKey(rootDirectory, PathFragment.create("a/c"), ImmutableSet.of()), |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 147 | graph)) |
| 148 | .isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 149 | } |
| 150 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 151 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 152 | public void testExcludedSubdirectoryGettingPassedDown() throws Exception { |
| 153 | // Given a package "a" with two packages below a directory below it, "a/b/c" and "a/b/d", |
| 154 | scratch.file("a/BUILD"); |
| 155 | scratch.file("a/b/c/BUILD"); |
| 156 | scratch.file("a/b/d/BUILD"); |
| 157 | |
| 158 | // When the top package is evaluated for recursive package values, and "a/b/c" is excluded, |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 159 | ImmutableSet<PathFragment> excludedPaths = ImmutableSet.of(PathFragment.create("a/b/c")); |
| 160 | SkyKey key = buildRecursivePkgKey(rootDirectory, PathFragment.create("a"), excludedPaths); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 161 | EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key); |
| 162 | RecursivePkgValue value = evaluationResult.get(key); |
| 163 | |
| 164 | // Then the package corresponding to the excluded subdirectory is not present in the result, |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 165 | assertThat(value.getPackages().toList()).doesNotContain("a/b/c"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 166 | |
| 167 | // And the top package and other subsubdirectory package are. |
ulfjack | 512244b | 2020-01-14 05:15:08 -0800 | [diff] [blame] | 168 | assertThat(value.getPackages().toList()).contains("a"); |
| 169 | assertThat(value.getPackages().toList()).contains("a/b/d"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 170 | |
| 171 | // Also, the computation graph contains a cached value for "a/b" with "a/b/c" excluded, because |
| 172 | // "a/b/c" does live underneath "a/b". |
| 173 | WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 174 | assertThat( |
| 175 | exists( |
| 176 | buildRecursivePkgKey(rootDirectory, PathFragment.create("a/b"), excludedPaths), |
| 177 | graph)) |
| 178 | .isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 179 | } |
| 180 | } |