blob: 883ed4d982d4a84117c97ecf92089a0313e666c8 [file] [log] [blame]
shreyax246f0aa2018-02-23 07:46:54 -08001// Copyright 2018 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.
14package com.google.devtools.build.lib.skyframe;
15
16import static com.google.common.truth.Truth.assertThat;
17import static org.mockito.Mockito.when;
18
19import com.google.common.collect.ImmutableMap;
20import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
21import com.google.devtools.build.lib.cmdline.Label;
22import com.google.devtools.build.lib.cmdline.PackageIdentifier;
23import com.google.devtools.build.lib.packages.NoSuchPackageException;
24import com.google.devtools.build.lib.packages.NoSuchTargetException;
25import com.google.devtools.build.lib.packages.Package;
26import com.google.devtools.build.lib.skyframe.TransitiveBaseTraversalFunction.TargetAndErrorIfAnyImpl;
adonovanc2fe3d82020-09-29 13:49:55 -070027import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
shreyax246f0aa2018-02-23 07:46:54 -080028import com.google.devtools.build.lib.util.GroupedList;
29import com.google.devtools.build.lib.util.GroupedList.GroupedListHelper;
adonovanc2fe3d82020-09-29 13:49:55 -070030import com.google.devtools.build.skyframe.EvaluationResult;
shreyax246f0aa2018-02-23 07:46:54 -080031import com.google.devtools.build.skyframe.SkyFunction;
32import com.google.devtools.build.skyframe.SkyKey;
janakrf091f9c2019-03-25 13:42:18 -070033import com.google.devtools.build.skyframe.ValueOrException2;
34import com.google.devtools.build.skyframe.ValueOrUntypedException;
shreyax246f0aa2018-02-23 07:46:54 -080035import java.util.concurrent.atomic.AtomicBoolean;
36import org.junit.Test;
37import org.junit.runner.RunWith;
38import org.junit.runners.JUnit4;
Googlera6705772019-05-28 09:39:18 -070039import org.mockito.ArgumentMatchers;
shreyax246f0aa2018-02-23 07:46:54 -080040import org.mockito.Mockito;
41
42/** Test for {@link TransitiveTraversalFunction}. */
43@RunWith(JUnit4.class)
44public class TransitiveTraversalFunctionTest extends BuildViewTestCase {
45
46 @Test
47 public void noRepeatedLabelVisitationForTransitiveTraversalFunction() throws Exception {
48 // Create a basic package with a target //foo:foo.
dannark90e2b4b2018-06-27 13:35:04 -070049 Label label = Label.parseAbsolute("//foo:foo", ImmutableMap.of());
adonovanc2fe3d82020-09-29 13:49:55 -070050 scratch.file("foo/BUILD", "sh_library(name = '" + label.getName() + "')");
51 Package pkg = loadPackage(label.getPackageIdentifier());
shreyax246f0aa2018-02-23 07:46:54 -080052 TargetAndErrorIfAnyImpl targetAndErrorIfAny =
53 new TargetAndErrorIfAnyImpl(
54 /*packageLoadedSuccessfully=*/ true,
55 /*errorLoadingTarget=*/ null,
56 pkg.getTarget(label.getName()));
57 TransitiveTraversalFunction function =
58 new TransitiveTraversalFunction() {
59 @Override
ulfjack731451f2019-05-09 04:30:35 -070060 TargetAndErrorIfAny loadTarget(Environment env, Label label) {
shreyax246f0aa2018-02-23 07:46:54 -080061 return targetAndErrorIfAny;
62 }
63 };
64 // Create the GroupedList saying we had already requested two targets the last time we called
65 // #compute.
66 GroupedListHelper<SkyKey> helper = new GroupedListHelper<>();
dannark90e2b4b2018-06-27 13:35:04 -070067 SkyKey fakeDep1 = function.getKey(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
68 SkyKey fakeDep2 = function.getKey(Label.parseAbsolute("//foo:baz", ImmutableMap.of()));
shreyax246f0aa2018-02-23 07:46:54 -080069 helper.add(PackageValue.key(label.getPackageIdentifier()));
70 helper.startGroup();
71 // Note that these targets don't actually exist in the package we created initially. It doesn't
72 // matter for the purpose of this test, the original package was just to create some objects
73 // that we needed.
74 helper.add(fakeDep1);
75 helper.add(fakeDep2);
76 helper.endGroup();
77 GroupedList<SkyKey> groupedList = new GroupedList<>();
78 groupedList.append(helper);
79 AtomicBoolean wasOptimizationUsed = new AtomicBoolean(false);
80 SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
81 when(mockEnv.getTemporaryDirectDeps()).thenReturn(groupedList);
82 when(mockEnv.getValuesOrThrow(
ulfjack731451f2019-05-09 04:30:35 -070083 groupedList.get(1), NoSuchPackageException.class, NoSuchTargetException.class))
shreyax246f0aa2018-02-23 07:46:54 -080084 .thenAnswer(
85 (invocationOnMock) -> {
86 wasOptimizationUsed.set(true);
87 // It doesn't matter what this map is, we'll return false in the valuesMissing() call.
88 return ImmutableMap.of();
89 });
90 when(mockEnv.valuesMissing()).thenReturn(true);
91
92 // Run the compute function and check that we returned null.
93 assertThat(function.compute(function.getKey(label), mockEnv)).isNull();
94
95 // Verify that the mock was called with the arguments we expected.
96 assertThat(wasOptimizationUsed.get()).isTrue();
97 }
98
janakrf091f9c2019-03-25 13:42:18 -070099 @Test
100 public void multipleErrorsForTransitiveTraversalFunction() throws Exception {
101 Label label = Label.parseAbsolute("//foo:foo", ImmutableMap.of());
adonovanc2fe3d82020-09-29 13:49:55 -0700102 scratch.file(
103 "foo/BUILD", "sh_library(name = '" + label.getName() + "', deps = [':bar', ':baz'])");
104 Package pkg = loadPackage(label.getPackageIdentifier());
janakrf091f9c2019-03-25 13:42:18 -0700105 TargetAndErrorIfAnyImpl targetAndErrorIfAny =
106 new TargetAndErrorIfAnyImpl(
107 /*packageLoadedSuccessfully=*/ true,
108 /*errorLoadingTarget=*/ null,
109 pkg.getTarget(label.getName()));
110 TransitiveTraversalFunction function =
111 new TransitiveTraversalFunction() {
112 @Override
ulfjack731451f2019-05-09 04:30:35 -0700113 TargetAndErrorIfAny loadTarget(Environment env, Label label) {
janakrf091f9c2019-03-25 13:42:18 -0700114 return targetAndErrorIfAny;
115 }
116 };
117 SkyKey dep1 = function.getKey(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
118 SkyKey dep2 = function.getKey(Label.parseAbsolute("//foo:baz", ImmutableMap.of()));
119 ImmutableMap<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>>
120 returnedDeps =
121 ImmutableMap.of(dep1, makeException("bad bar"), dep2, makeException("bad baz"));
122 SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
123 // Try two evaluations, with the environment reversing the order of the map it returns.
124 when(mockEnv.getValuesOrThrow(
Googlera6705772019-05-28 09:39:18 -0700125 ArgumentMatchers.any(),
janakrf091f9c2019-03-25 13:42:18 -0700126 Mockito.eq(NoSuchPackageException.class),
127 Mockito.eq(NoSuchTargetException.class)))
128 .thenReturn(returnedDeps);
129 when(mockEnv.valuesMissing()).thenReturn(false);
130
131 assertThat(
132 ((TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv))
133 .getErrorMessage())
134 .isEqualTo("bad bar");
135 ImmutableMap<SkyKey, ValueOrException2<NoSuchPackageException, NoSuchTargetException>>
136 reversedDeps =
137 ImmutableMap.of(dep2, makeException("bad baz"), dep1, makeException("bad bar"));
138 when(mockEnv.getValuesOrThrow(
Googlera6705772019-05-28 09:39:18 -0700139 ArgumentMatchers.any(),
janakrf091f9c2019-03-25 13:42:18 -0700140 Mockito.eq(NoSuchPackageException.class),
141 Mockito.eq(NoSuchTargetException.class)))
142 .thenReturn(reversedDeps);
143 assertThat(
144 ((TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv))
145 .getErrorMessage())
146 .isEqualTo("bad bar");
147 }
148
149 @Test
150 public void selfErrorWins() throws Exception {
151 Label label = Label.parseAbsolute("//foo:foo", ImmutableMap.of());
adonovanc2fe3d82020-09-29 13:49:55 -0700152 scratch.file(
153 "foo/BUILD", "sh_library(name = '" + label.getName() + "', deps = [':bar', ':baz'])");
154 Package pkg = loadPackage(label.getPackageIdentifier());
janakrf091f9c2019-03-25 13:42:18 -0700155 TargetAndErrorIfAnyImpl targetAndErrorIfAny =
156 new TargetAndErrorIfAnyImpl(
157 /*packageLoadedSuccessfully=*/ true,
158 /*errorLoadingTarget=*/ new NoSuchTargetException("self error is long and last"),
159 pkg.getTarget(label.getName()));
160 TransitiveTraversalFunction function =
161 new TransitiveTraversalFunction() {
162 @Override
ulfjack731451f2019-05-09 04:30:35 -0700163 TargetAndErrorIfAny loadTarget(Environment env, Label label) {
janakrf091f9c2019-03-25 13:42:18 -0700164 return targetAndErrorIfAny;
165 }
166 };
167 SkyKey dep = function.getKey(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
168 SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
169 when(mockEnv.getValuesOrThrow(
Googlera6705772019-05-28 09:39:18 -0700170 ArgumentMatchers.any(),
janakrf091f9c2019-03-25 13:42:18 -0700171 Mockito.eq(NoSuchPackageException.class),
172 Mockito.eq(NoSuchTargetException.class)))
173 .thenReturn(ImmutableMap.of(dep, makeException("bad bar")));
174 when(mockEnv.valuesMissing()).thenReturn(false);
175
ulfjack731451f2019-05-09 04:30:35 -0700176 TransitiveTraversalValue transitiveTraversalValue =
177 (TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv);
178 assertThat(transitiveTraversalValue.getErrorMessage()).isEqualTo("self error is long and last");
janakrf091f9c2019-03-25 13:42:18 -0700179 }
180
181 private static ValueOrException2<NoSuchPackageException, NoSuchTargetException> makeException(
182 String errorMessage) {
183 ValueOrUntypedException exn =
184 ValueOrUntypedException.ofExn(new NoSuchTargetException(errorMessage));
185 return ValueOrException2.fromUntypedException(
186 exn, NoSuchPackageException.class, NoSuchTargetException.class);
187 }
188
adonovanc2fe3d82020-09-29 13:49:55 -0700189 /* Invokes the loading phase, using Skyframe. */
190 private Package loadPackage(PackageIdentifier pkgid)
191 throws InterruptedException, NoSuchPackageException {
192 SkyKey key = PackageValue.key(pkgid);
193 EvaluationResult<PackageValue> result =
194 SkyframeExecutorTestUtils.evaluate(
195 getSkyframeExecutor(), key, /*keepGoing=*/ false, reporter);
196 if (result.hasError()) {
197 throw (NoSuchPackageException) result.getError(key).getException();
198 }
199 return result.get(key).getPackage();
shreyax246f0aa2018-02-23 07:46:54 -0800200 }
201}