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; |
| 22 | import com.google.common.collect.Iterables; |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 23 | import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; |
Kristina Chodorow | a1a31ff | 2016-07-27 16:34:27 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.cmdline.RepositoryName; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 25 | import com.google.devtools.build.lib.vfs.Path; |
| 26 | import com.google.devtools.build.lib.vfs.PathFragment; |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 27 | import com.google.devtools.build.lib.vfs.Root; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 28 | import com.google.devtools.build.lib.vfs.RootedPath; |
| 29 | import com.google.devtools.build.skyframe.BuildDriver; |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 30 | import com.google.devtools.build.skyframe.EvaluationContext; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 31 | import com.google.devtools.build.skyframe.EvaluationResult; |
| 32 | import com.google.devtools.build.skyframe.SkyKey; |
| 33 | import com.google.devtools.build.skyframe.WalkableGraph; |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 34 | import org.junit.Before; |
| 35 | import org.junit.Test; |
| 36 | import org.junit.runner.RunWith; |
| 37 | import org.junit.runners.JUnit4; |
| 38 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 39 | /** |
| 40 | * Tests for {@link RecursivePkgFunction}. Unfortunately, we can't directly test |
| 41 | * RecursivePkgFunction as it uses PackageValues, and PackageFunction uses legacy stuff that |
| 42 | * isn't easily mockable. So our testing strategy is to make hacky calls to |
| 43 | * SequencedSkyframeExecutor. |
| 44 | * |
| 45 | * <p>Target parsing tests already cover most of the behavior of RecursivePkgFunction, but there |
| 46 | * are a couple of corner cases we need to test directly. |
| 47 | */ |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 48 | @RunWith(JUnit4.class) |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 49 | public class RecursivePkgFunctionTest extends BuildViewTestCase { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 50 | |
| 51 | private SkyframeExecutor skyframeExecutor; |
| 52 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 53 | @Before |
| 54 | public final void createSkyframeExecutor() throws Exception { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 55 | skyframeExecutor = getSkyframeExecutor(); |
| 56 | } |
| 57 | |
| 58 | private SkyKey buildRecursivePkgKey( |
| 59 | Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) { |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 60 | RootedPath rootedPath = RootedPath.toRootedPath(Root.fromPath(root), rootRelativePath); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 61 | return RecursivePkgValue.key( |
Kristina Chodorow | a1a31ff | 2016-07-27 16:34:27 +0000 | [diff] [blame] | 62 | RepositoryName.MAIN, rootedPath, excludedPaths); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | private RecursivePkgValue buildRecursivePkgValue(Path root, PathFragment rootRelativePath) |
| 66 | throws Exception { |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 67 | return buildRecursivePkgValue(root, rootRelativePath, ImmutableSet.of()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | private RecursivePkgValue buildRecursivePkgValue( |
| 71 | Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) |
| 72 | throws Exception { |
| 73 | SkyKey key = buildRecursivePkgKey(root, rootRelativePath, excludedPaths); |
| 74 | return getEvaluationResult(key).get(key); |
| 75 | } |
| 76 | |
| 77 | private EvaluationResult<RecursivePkgValue> getEvaluationResult(SkyKey key) |
| 78 | throws InterruptedException { |
| 79 | BuildDriver driver = skyframeExecutor.getDriverForTesting(); |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 80 | EvaluationContext evaluationContext = |
| 81 | EvaluationContext.newBuilder() |
| 82 | .setKeepGoing(false) |
| 83 | .setNumThreads(SequencedSkyframeExecutor.DEFAULT_THREAD_COUNT) |
| 84 | .setEventHander(reporter) |
| 85 | .build(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 86 | EvaluationResult<RecursivePkgValue> evaluationResult = |
Googler | 1002867 | 2018-10-25 12:14:34 -0700 | [diff] [blame] | 87 | driver.evaluate(ImmutableList.of(key), evaluationContext); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 88 | Preconditions.checkState(!evaluationResult.hasError()); |
| 89 | return evaluationResult; |
| 90 | } |
| 91 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 92 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 93 | public void testStartingAtBuildFile() throws Exception { |
| 94 | scratch.file("a/b/c/BUILD"); |
| 95 | RecursivePkgValue value = |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 96 | buildRecursivePkgValue(rootDirectory, PathFragment.create("a/b/c/BUILD")); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 97 | assertThat(value.getPackages().isEmpty()).isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 98 | } |
| 99 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 100 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 101 | public void testPackagesUnderMultipleRoots() throws Exception { |
carmi | e3824d4 | 2018-04-03 14:58:26 -0700 | [diff] [blame] | 102 | // PackageLoader doesn't support --package_path. |
| 103 | initializeSkyframeExecutor(/*doPackageLoadingChecks=*/ false); |
| 104 | skyframeExecutor = getSkyframeExecutor(); |
| 105 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 106 | Path root1 = rootDirectory.getRelative("root1"); |
| 107 | Path root2 = rootDirectory.getRelative("root2"); |
| 108 | scratch.file(root1 + "/WORKSPACE"); |
| 109 | scratch.file(root2 + "/WORKSPACE"); |
| 110 | scratch.file(root1 + "/a/BUILD"); |
| 111 | scratch.file(root2 + "/a/b/BUILD"); |
| 112 | setPackageCacheOptions("--package_path=" + "root1" + ":" + "root2"); |
| 113 | |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 114 | RecursivePkgValue valueForRoot1 = buildRecursivePkgValue(root1, PathFragment.create("a")); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 115 | String root1Pkg = Iterables.getOnlyElement(valueForRoot1.getPackages()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 116 | assertThat(root1Pkg).isEqualTo("a"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 117 | |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 118 | RecursivePkgValue valueForRoot2 = buildRecursivePkgValue(root2, PathFragment.create("a")); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 119 | String root2Pkg = Iterables.getOnlyElement(valueForRoot2.getPackages()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 120 | assertThat(root2Pkg).isEqualTo("a/b"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 121 | } |
| 122 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 123 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 124 | public void testSubdirectoryExclusion() throws Exception { |
| 125 | // Given a package "a" with two packages below it, "a/b" and "a/c", |
| 126 | scratch.file("a/BUILD"); |
| 127 | scratch.file("a/b/BUILD"); |
| 128 | scratch.file("a/c/BUILD"); |
| 129 | |
| 130 | // 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] | 131 | PathFragment excludedPathFragment = PathFragment.create("a/b"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 132 | SkyKey key = |
| 133 | buildRecursivePkgKey( |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 134 | rootDirectory, PathFragment.create("a"), ImmutableSet.of(excludedPathFragment)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 135 | EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key); |
| 136 | RecursivePkgValue value = evaluationResult.get(key); |
| 137 | |
| 138 | // Then the package corresponding to "a/b" is not present in the result, |
| 139 | assertThat(value.getPackages()).doesNotContain("a/b"); |
| 140 | |
| 141 | // And the "a" package and "a/c" package are. |
| 142 | assertThat(value.getPackages()).contains("a"); |
| 143 | assertThat(value.getPackages()).contains("a/c"); |
| 144 | |
| 145 | // Also, the computation graph does not contain a cached value for "a/b". |
| 146 | WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 147 | assertThat( |
| 148 | exists( |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 149 | buildRecursivePkgKey(rootDirectory, excludedPathFragment, ImmutableSet.of()), |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 150 | graph)) |
| 151 | .isFalse(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 152 | |
| 153 | // And the computation graph does contain a cached value for "a/c" with the empty set excluded, |
| 154 | // because that key was evaluated. |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 155 | assertThat( |
| 156 | exists( |
carmi | d6a9828 | 2018-03-13 19:19:16 -0700 | [diff] [blame] | 157 | buildRecursivePkgKey(rootDirectory, PathFragment.create("a/c"), ImmutableSet.of()), |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 158 | graph)) |
| 159 | .isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 160 | } |
| 161 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 162 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 163 | public void testExcludedSubdirectoryGettingPassedDown() throws Exception { |
| 164 | // Given a package "a" with two packages below a directory below it, "a/b/c" and "a/b/d", |
| 165 | scratch.file("a/BUILD"); |
| 166 | scratch.file("a/b/c/BUILD"); |
| 167 | scratch.file("a/b/d/BUILD"); |
| 168 | |
| 169 | // 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] | 170 | ImmutableSet<PathFragment> excludedPaths = ImmutableSet.of(PathFragment.create("a/b/c")); |
| 171 | SkyKey key = buildRecursivePkgKey(rootDirectory, PathFragment.create("a"), excludedPaths); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 172 | EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key); |
| 173 | RecursivePkgValue value = evaluationResult.get(key); |
| 174 | |
| 175 | // Then the package corresponding to the excluded subdirectory is not present in the result, |
| 176 | assertThat(value.getPackages()).doesNotContain("a/b/c"); |
| 177 | |
| 178 | // And the top package and other subsubdirectory package are. |
| 179 | assertThat(value.getPackages()).contains("a"); |
| 180 | assertThat(value.getPackages()).contains("a/b/d"); |
| 181 | |
| 182 | // Also, the computation graph contains a cached value for "a/b" with "a/b/c" excluded, because |
| 183 | // "a/b/c" does live underneath "a/b". |
| 184 | WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph()); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 185 | assertThat( |
| 186 | exists( |
| 187 | buildRecursivePkgKey(rootDirectory, PathFragment.create("a/b"), excludedPaths), |
| 188 | graph)) |
| 189 | .isTrue(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 190 | } |
| 191 | } |