blob: 04724e1910fd0bc443b36612f610a7f08fa88ded [file] [log] [blame]
messa634bd842021-02-26 04:54:05 -08001// Copyright 2021 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
15package com.google.devtools.build.lib.starlark;
16
17import static com.google.common.truth.Truth.assertThat;
18import static com.google.common.truth.Truth8.assertThat;
19import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ACTION_OWNER;
20import static org.mockito.Mockito.mock;
21import static org.mockito.Mockito.when;
22
23import com.google.common.collect.ImmutableMap;
24import com.google.common.collect.Sets;
25import com.google.devtools.build.lib.actions.Action;
26import com.google.devtools.build.lib.actions.ActionExecutionContext;
27import com.google.devtools.build.lib.actions.ActionExecutionContext.LostInputsCheck;
messa634bd842021-02-26 04:54:05 -080028import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
29import com.google.devtools.build.lib.actions.Artifact;
30import com.google.devtools.build.lib.actions.Executor;
janakr13b737a2021-07-02 14:24:25 -070031import com.google.devtools.build.lib.actions.ThreadStateReceiver;
messa634bd842021-02-26 04:54:05 -080032import com.google.devtools.build.lib.analysis.actions.StarlarkAction;
33import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil;
34import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
35import com.google.devtools.build.lib.collect.nestedset.NestedSet;
36import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
37import com.google.devtools.build.lib.collect.nestedset.NestedSetExpander;
38import com.google.devtools.build.lib.collect.nestedset.Order;
39import com.google.devtools.build.lib.exec.BinTools;
40import com.google.devtools.build.lib.exec.util.TestExecutorBuilder;
41import com.google.devtools.build.lib.vfs.PathFragment;
twerthd05f92e2021-05-11 05:45:32 -070042import com.google.devtools.build.lib.vfs.UnixGlob;
messa5bff6012021-03-17 03:42:23 -070043import java.util.LinkedHashMap;
44import java.util.Map;
messa634bd842021-02-26 04:54:05 -080045import java.util.Optional;
46import org.junit.Before;
47import org.junit.Test;
48import org.junit.runner.RunWith;
49import org.junit.runners.JUnit4;
50import org.mockito.ArgumentMatchers;
51
52/** Tests for {@link StarlarkAction} using the shadowed action parameter. */
53@RunWith(JUnit4.class)
54public final class StarlarkActionWithShadowedActionTest extends BuildViewTestCase {
55
messa634bd842021-02-26 04:54:05 -080056 private ActionExecutionContext executionContext;
57 private AnalysisTestUtil.CollectingAnalysisEnvironment collectingAnalysisEnvironment;
58 private NestedSet<Artifact> starlarkActionInputs;
59 private NestedSet<Artifact> shadowedActionInputs;
60 private NestedSet<Artifact> discoveredInputs;
messa5bff6012021-03-17 03:42:23 -070061 private Map<String, String> starlarkActionEnvironment;
62 private Map<String, String> shadowedActionEnvironment;
messa634bd842021-02-26 04:54:05 -080063
64 private Artifact output;
65 private PathFragment executable;
66
67 @Before
68 public final void createArtifacts() throws Exception {
69 collectingAnalysisEnvironment =
70 new AnalysisTestUtil.CollectingAnalysisEnvironment(getTestAnalysisEnvironment());
71 starlarkActionInputs =
72 NestedSetBuilder.create(
73 Order.STABLE_ORDER,
74 getSourceArtifact("pkg/shadowed_action_inp1"),
75 getSourceArtifact("pkg/discovered_inp2"),
76 getSourceArtifact("pkg/starlark_action_inp3"));
77 shadowedActionInputs =
78 NestedSetBuilder.create(
79 Order.STABLE_ORDER,
80 getSourceArtifact("pkg/shadowed_action_inp1"),
81 getSourceArtifact("pkg/shadowed_action_inp2"),
82 getSourceArtifact("pkg/shadowed_action_inp3"));
83 discoveredInputs =
84 NestedSetBuilder.create(
85 Order.STABLE_ORDER,
86 getSourceArtifact("pkg/shadowed_action_inp1"),
87 getSourceArtifact("pkg/discovered_inp2"),
88 getSourceArtifact("pkg/discovered_inp3"));
89 output = getBinArtifactWithNoOwner("output");
90 executable = scratch.file("/bin/xxx").asFragment();
messa5bff6012021-03-17 03:42:23 -070091 starlarkActionEnvironment =
92 ImmutableMap.of(
93 "repeated_var", "starlark_val",
94 "a_var", "a_val",
95 "b_var", "b_val");
96 shadowedActionEnvironment =
97 ImmutableMap.of(
98 "repeated_var", "shadowed_val",
99 "c_var", "c_val",
100 "d_var", "d_val");
messa634bd842021-02-26 04:54:05 -0800101 }
102
103 @Before
104 public final void createExecutorAndContext() throws Exception {
105 BinTools binTools = BinTools.forUnitTesting(directories, analysisMock.getEmbeddedTools());
messa5bff6012021-03-17 03:42:23 -0700106 Executor executor = new TestExecutorBuilder(fileSystem, directories, binTools).build();
messa634bd842021-02-26 04:54:05 -0800107 executionContext =
108 new ActionExecutionContext(
109 executor,
110 /*actionInputFileCache=*/ null,
111 ActionInputPrefetcher.NONE,
112 actionKeyContext,
113 /*metadataHandler=*/ null,
114 /*rewindingEnabled=*/ false,
115 LostInputsCheck.NONE,
116 /*fileOutErr=*/ null,
117 /*eventHandler=*/ null,
118 /*clientEnv=*/ ImmutableMap.of(),
119 /*topLevelFilesets=*/ ImmutableMap.of(),
120 /*artifactExpander=*/ null,
121 /*actionFileSystem=*/ null,
122 /*skyframeDepsResult=*/ null,
twerthd05f92e2021-05-11 05:45:32 -0700123 NestedSetExpander.DEFAULT,
janakr13b737a2021-07-02 14:24:25 -0700124 UnixGlob.DEFAULT_SYSCALLS,
125 ThreadStateReceiver.NULL_INSTANCE);
messa634bd842021-02-26 04:54:05 -0800126 }
127
128 @Test
129 public void testUsingOnlyShadowedActionInputs() throws Exception {
130 // If both starlark action and the shadowed action do not have inputs, then getInputs of both of
131 // them should return empty set
132 Action shadowedAction =
133 createShadowedAction(
134 NestedSetBuilder.emptySet(Order.STABLE_ORDER), /*discoversInputs=*/ false, null);
janakrd4591972021-04-14 08:37:06 -0700135 StarlarkAction starlarkAction =
136 (StarlarkAction)
137 new StarlarkAction.Builder()
138 .setShadowedAction(Optional.of(shadowedAction))
139 .setExecutable(executable)
140 .addOutput(output)
141 .build(NULL_ACTION_OWNER, targetConfig);
142 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800143
144 assertThat(starlarkAction.getInputs().toList()).isEmpty();
145 assertThat(starlarkAction.discoversInputs()).isFalse();
146 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
147 assertThat(starlarkAction.getAllowedDerivedInputs().toList()).isEmpty();
148
149 // If the starlark action does not have any inputs, then it will use the shadowed action inputs
150 shadowedAction = createShadowedAction(shadowedActionInputs, false, null);
janakrd4591972021-04-14 08:37:06 -0700151 starlarkAction =
152 (StarlarkAction)
153 new StarlarkAction.Builder()
154 .setShadowedAction(Optional.of(shadowedAction))
155 .setExecutable(executable)
156 .addOutput(output)
157 .build(NULL_ACTION_OWNER, targetConfig);
158 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800159
160 assertThat(starlarkAction.getInputs().toList())
161 .containsExactlyElementsIn(shadowedActionInputs.toList());
162 assertThat(starlarkAction.discoversInputs()).isFalse();
163 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
164 assertThat(starlarkAction.getAllowedDerivedInputs().toList())
165 .containsExactlyElementsIn(shadowedActionInputs.toList());
166 }
167
168 @Test
169 public void testUsingOnlyShadowedActionWithDiscoveredInputs() throws Exception {
170 // Test that the shadowed action's discovered inputs are passed to the starlark action
171 Action shadowedAction =
172 createShadowedAction(
173 NestedSetBuilder.emptySet(Order.STABLE_ORDER),
174 /*discoversInputs=*/ true,
175 discoveredInputs);
janakrd4591972021-04-14 08:37:06 -0700176 StarlarkAction starlarkAction =
177 (StarlarkAction)
178 new StarlarkAction.Builder()
179 .setShadowedAction(Optional.of(shadowedAction))
180 .setExecutable(executable)
181 .addOutput(output)
182 .build(NULL_ACTION_OWNER, targetConfig);
183 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800184
185 assertThat(starlarkAction.getInputs().toList()).isEmpty();
186 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
187 assertThat(starlarkAction.getAllowedDerivedInputs().toList()).isEmpty();
188 assertThat(starlarkAction.discoversInputs()).isTrue();
189 assertThat(starlarkAction.discoverInputs(executionContext).toList())
190 .containsExactlyElementsIn(discoveredInputs.toList());
191 // after discovering inputs, the starlark action inputs should be updated
192 assertThat(starlarkAction.inputsDiscovered()).isTrue();
193 assertThat(starlarkAction.getInputs().toList())
194 .containsExactlyElementsIn(discoveredInputs.toList());
195
196 // Test that both inputs and discovered inputs of the shadowed action are passed to the starlark
197 // action
198 shadowedAction = createShadowedAction(shadowedActionInputs, true, discoveredInputs);
janakrd4591972021-04-14 08:37:06 -0700199 starlarkAction =
200 (StarlarkAction)
201 new StarlarkAction.Builder()
202 .setShadowedAction(Optional.of(shadowedAction))
203 .setExecutable(executable)
204 .addOutput(output)
205 .build(NULL_ACTION_OWNER, targetConfig);
206 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800207
208 assertThat(starlarkAction.getInputs().toList())
209 .containsExactlyElementsIn(shadowedActionInputs.toList());
210 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
211 assertThat(starlarkAction.getAllowedDerivedInputs().toList())
212 .containsExactlyElementsIn(shadowedActionInputs.toList());
213 assertThat(starlarkAction.discoversInputs()).isTrue();
214 assertThat(starlarkAction.discoverInputs(executionContext).toList())
215 .containsExactlyElementsIn(
216 Sets.<Artifact>difference(discoveredInputs.toSet(), shadowedActionInputs.toSet())
217 .toArray());
218 // after discovering inputs, the starlark action inputs should be updated
219 assertThat(starlarkAction.inputsDiscovered()).isTrue();
220 assertThat(starlarkAction.getInputs().toList())
221 .containsExactlyElementsIn(
222 Sets.<Artifact>union(shadowedActionInputs.toSet(), discoveredInputs.toSet()).toArray());
223 }
224
225 @Test
226 public void testUsingShadowedActionWithStarlarkActionInputs() throws Exception {
227 // Test using Starlark action's inputs without using a shadowed action
janakrd4591972021-04-14 08:37:06 -0700228 StarlarkAction starlarkAction =
229 (StarlarkAction)
230 new StarlarkAction.Builder()
231 .setExecutable(executable)
232 .addInput(starlarkActionInputs.toList().get(0))
233 .addInput(starlarkActionInputs.toList().get(1))
234 .addInput(starlarkActionInputs.toList().get(2))
235 .addOutput(output)
236 .build(NULL_ACTION_OWNER, targetConfig);
237 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800238
239 assertThat(starlarkAction.getInputs().toList())
240 .containsExactlyElementsIn(starlarkActionInputs.toList());
241 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
242 assertThat(starlarkAction.getAllowedDerivedInputs().toList())
243 .containsExactlyElementsIn(starlarkActionInputs.toList());
244 assertThat(starlarkAction.discoversInputs()).isFalse();
245
246 // Test using Starlark actions's inputs with shadowed action's inputs
247 Action shadowedAction =
248 createShadowedAction(
249 shadowedActionInputs, /*discoversInputs=*/ false, /*discoveredInputs=*/ null);
janakrd4591972021-04-14 08:37:06 -0700250 starlarkAction =
251 (StarlarkAction)
252 new StarlarkAction.Builder()
253 .setShadowedAction(Optional.of(shadowedAction))
254 .setExecutable(executable)
255 .addInput(starlarkActionInputs.toList().get(0))
256 .addInput(starlarkActionInputs.toList().get(1))
257 .addInput(starlarkActionInputs.toList().get(2))
258 .addOutput(output)
259 .build(NULL_ACTION_OWNER, targetConfig);
260 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800261
262 assertThat(starlarkAction.getInputs().toList())
263 .containsExactlyElementsIn(
264 Sets.<Artifact>union(shadowedActionInputs.toSet(), starlarkActionInputs.toSet())
265 .toArray());
266 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
267 assertThat(starlarkAction.getAllowedDerivedInputs().toList())
268 .containsExactlyElementsIn(
269 Sets.<Artifact>union(shadowedActionInputs.toSet(), starlarkActionInputs.toSet())
270 .toArray());
271 assertThat(starlarkAction.discoversInputs()).isFalse();
272
273 // Test using Starlark actions's inputs with shadowed action's inputs and discovered inputs
274 shadowedAction = createShadowedAction(shadowedActionInputs, true, discoveredInputs);
janakrd4591972021-04-14 08:37:06 -0700275 starlarkAction =
276 (StarlarkAction)
277 new StarlarkAction.Builder()
278 .setShadowedAction(Optional.of(shadowedAction))
279 .setExecutable(executable)
280 .addInput(starlarkActionInputs.toList().get(0))
281 .addInput(starlarkActionInputs.toList().get(1))
282 .addInput(starlarkActionInputs.toList().get(2))
283 .addOutput(output)
284 .build(NULL_ACTION_OWNER, targetConfig);
285 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa634bd842021-02-26 04:54:05 -0800286
287 assertThat(starlarkAction.getInputs().toList())
288 .containsExactlyElementsIn(
289 Sets.<Artifact>union(shadowedActionInputs.toSet(), starlarkActionInputs.toSet())
290 .toArray());
291 assertThat(starlarkAction.getUnusedInputsList()).isEmpty();
292 assertThat(starlarkAction.getAllowedDerivedInputs().toList())
293 .containsExactlyElementsIn(
294 Sets.<Artifact>union(shadowedActionInputs.toSet(), starlarkActionInputs.toSet())
295 .toArray());
296 assertThat(starlarkAction.discoversInputs()).isTrue();
297 assertThat(starlarkAction.discoverInputs(executionContext).toList())
298 .containsExactly(discoveredInputs.toList().get(2));
299 // after discovering inputs, the starlark action inputs should be updated
300 assertThat(starlarkAction.inputsDiscovered()).isTrue();
301 assertThat(starlarkAction.getInputs().toList())
302 .containsExactlyElementsIn(
303 Sets.<Artifact>union(
304 NestedSetBuilder.wrap(
305 Order.STABLE_ORDER,
306 Sets.<Artifact>union(
307 shadowedActionInputs.toSet(), starlarkActionInputs.toSet()))
308 .toSet(),
309 discoveredInputs.toSet())
310 .toArray());
311 }
312
messa5bff6012021-03-17 03:42:23 -0700313 @Test
314 public void testPassingShadowedActionEnvironment() throws Exception {
315 // Test using Starlark action's environment without using a shadowed action
janakrd4591972021-04-14 08:37:06 -0700316 StarlarkAction starlarkAction =
317 (StarlarkAction)
318 new StarlarkAction.Builder()
319 .setExecutable(executable)
320 .addInput(starlarkActionInputs.toList().get(0))
321 .addOutput(output)
322 .setEnvironment(starlarkActionEnvironment)
323 .build(NULL_ACTION_OWNER, targetConfig);
324 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa5bff6012021-03-17 03:42:23 -0700325
326 assertThat(starlarkAction.getEffectiveEnvironment(ImmutableMap.of()))
327 .containsExactlyEntriesIn(starlarkActionEnvironment);
328
329 // Test using shadowed action's environment without Starlark actions's environment
330 Action shadowedAction =
331 createShadowedAction(
332 shadowedActionInputs, /*discoversInputs=*/ false, /*discoveredInputs=*/ null);
janakrd4591972021-04-14 08:37:06 -0700333 starlarkAction =
334 (StarlarkAction)
335 new StarlarkAction.Builder()
336 .setShadowedAction(Optional.of(shadowedAction))
337 .setExecutable(executable)
338 .addInput(starlarkActionInputs.toList().get(0))
339 .addOutput(output)
340 .build(NULL_ACTION_OWNER, targetConfig);
341 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa5bff6012021-03-17 03:42:23 -0700342
343 assertThat(starlarkAction.getEffectiveEnvironment(ImmutableMap.of()))
344 .containsExactlyEntriesIn(shadowedActionEnvironment);
345
346 // Test using Starlark actions's environment with shadowed action's environment
janakrd4591972021-04-14 08:37:06 -0700347 starlarkAction =
348 (StarlarkAction)
349 new StarlarkAction.Builder()
350 .setShadowedAction(Optional.of(shadowedAction))
351 .setExecutable(executable)
352 .addInput(starlarkActionInputs.toList().get(0))
353 .addOutput(output)
354 .setEnvironment(starlarkActionEnvironment)
355 .build(NULL_ACTION_OWNER, targetConfig);
356 collectingAnalysisEnvironment.registerAction(starlarkAction);
messa5bff6012021-03-17 03:42:23 -0700357
358 LinkedHashMap<String, String> expectedEnvironment = new LinkedHashMap<>();
359 expectedEnvironment.putAll(shadowedActionEnvironment);
360 expectedEnvironment.putAll(starlarkActionEnvironment);
361
362 ImmutableMap<String, String> actualEnvironment =
363 starlarkAction.getEffectiveEnvironment(ImmutableMap.of());
364 assertThat(actualEnvironment).hasSize(5);
365 // Starlark action's env overwrites any repeated variable from the shadowed action env
366 assertThat(actualEnvironment).containsEntry("repeated_var", "starlark_val");
367 assertThat(actualEnvironment).containsExactlyEntriesIn(expectedEnvironment);
368 }
369
messa634bd842021-02-26 04:54:05 -0800370 private Action createShadowedAction(
371 NestedSet<Artifact> inputs, boolean discoversInputs, NestedSet<Artifact> discoveredInputs)
messa5bff6012021-03-17 03:42:23 -0700372 throws Exception {
messa634bd842021-02-26 04:54:05 -0800373 Action shadowedAction = mock(Action.class);
374 when(shadowedAction.discoversInputs()).thenReturn(discoversInputs);
375 when(shadowedAction.getInputs()).thenReturn(inputs);
376 when(shadowedAction.getAllowedDerivedInputs()).thenReturn(inputs);
377 when(shadowedAction.getInputFilesForExtraAction(
378 ArgumentMatchers.any(ActionExecutionContext.class)))
379 .thenReturn(discoveredInputs);
380 when(shadowedAction.inputsDiscovered()).thenReturn(true);
381 when(shadowedAction.getOwner()).thenReturn(NULL_ACTION_OWNER);
messa5bff6012021-03-17 03:42:23 -0700382 when(shadowedAction.getEffectiveEnvironment(ArgumentMatchers.anyMap()))
383 .thenReturn(ImmutableMap.copyOf(shadowedActionEnvironment));
messa634bd842021-02-26 04:54:05 -0800384
385 return shadowedAction;
386 }
387}