blob: 2788662a20be8962e107b448e0a9a34fd7109f78 [file] [log] [blame]
// Copyright 2022 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.analysis.extra;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ACTION_OWNER;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionContext;
import com.google.devtools.build.lib.actions.ActionEnvironment;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionExecutionContext.LostInputsCheck;
import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.ActionResult;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.actions.ArtifactRoot.RootType;
import com.google.devtools.build.lib.actions.CommandLine;
import com.google.devtools.build.lib.actions.DiscoveredModulesPruner;
import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.actions.SpawnStrategy;
import com.google.devtools.build.lib.actions.ThreadStateReceiver;
import com.google.devtools.build.lib.actions.extra.ExtraActionInfo;
import com.google.devtools.build.lib.actions.extra.JavaCompileInfo;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil.NullAction;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.exec.BlazeExecutor;
import com.google.devtools.build.lib.exec.util.TestExecutorBuilder;
import com.google.devtools.build.lib.testutil.FoundationTestCase;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.SyscallCache;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
/**
* Unit tests for ExtraAction class.
*/
@RunWith(JUnit4.class)
public class ExtraActionTest extends FoundationTestCase {
private final ActionKeyContext actionKeyContext = new ActionKeyContext();
private static class SpecifiedInfoAction extends NullAction {
private final ExtraActionInfo info;
private SpecifiedInfoAction(ExtraActionInfo info) {
this.info = info;
}
@Override
public ExtraActionInfo.Builder getExtraActionInfo(ActionKeyContext actionKeyContext) {
return info.toBuilder();
}
}
@Test
public void testExtraActionInfoAffectsMnemonic() throws Exception {
ExtraActionInfo infoOne = ExtraActionInfo.newBuilder()
.setExtension(
JavaCompileInfo.javaCompileInfo,
JavaCompileInfo.newBuilder().addSourceFile("one").build())
.build();
ExtraActionInfo infoTwo = ExtraActionInfo.newBuilder()
.setExtension(
JavaCompileInfo.javaCompileInfo,
JavaCompileInfo.newBuilder().addSourceFile("two").build())
.build();
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot root = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "out");
Artifact output = ActionsTestUtil.createArtifact(root, scratch.file("/out/test.out"));
Action actionOne = new ExtraActionInfoFileWriteAction(ActionsTestUtil.NULL_ACTION_OWNER, output,
new SpecifiedInfoAction(infoOne));
Action actionTwo = new ExtraActionInfoFileWriteAction(ActionsTestUtil.NULL_ACTION_OWNER, output,
new SpecifiedInfoAction(infoTwo));
assertThat(actionOne.getKey(actionKeyContext, /*artifactExpander=*/ null))
.isNotEqualTo(actionTwo.getKey(actionKeyContext, /*artifactExpander=*/ null));
}
/**
* Regression test. The Spawn created for extra actions needs to pass the environment of the extra
* action by getting the result of SpawnAction.getEnvironment() method instead of relying on the
* default field value of BaseSpawn.environment.
*/
@Test
public void testEnvironmentPassedOnOverwrite() throws Exception {
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot out = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "out");
ExtraAction extraAction =
new ExtraAction(
NestedSetBuilder.emptySet(Order.STABLE_ORDER),
EmptyRunfilesSupplier.INSTANCE,
ImmutableSet.of(
(Artifact.DerivedArtifact)
ActionsTestUtil.createArtifact(out, scratch.file("/out/test.out"))),
new NullAction(),
false,
CommandLine.of(Arrays.asList("one", "two", "thee")),
ActionEnvironment.create(ImmutableMap.of("TEST", "TEST_VALUE")),
ImmutableMap.of(),
"Executing extra action bla bla",
"bla bla");
final Map<String, String> spawnEnvironment = new HashMap<>();
SpawnStrategy fakeSpawnStrategy =
new SpawnStrategy() {
@Override
public ImmutableList<SpawnResult> exec(
Spawn spawn, ActionExecutionContext actionExecutionContext) {
spawnEnvironment.putAll(spawn.getEnvironment());
return ImmutableList.of();
}
@Override
public boolean canExec(
Spawn spawn, ActionContext.ActionContextRegistry actionContextRegistry) {
return true;
}
};
BlazeExecutor testExecutor =
new TestExecutorBuilder(fileSystem, execRoot, null)
.addStrategy(fakeSpawnStrategy, "fake")
.setDefaultStrategies("fake")
.build();
ActionResult actionResult =
extraAction.execute(
new ActionExecutionContext(
testExecutor,
/* inputMetadataProvider= */ null,
ActionInputPrefetcher.NONE,
actionKeyContext,
/* outputMetadataStore= */ null,
/* rewindingEnabled= */ false,
LostInputsCheck.NONE,
/* fileOutErr= */ null,
/* eventHandler= */ null,
/* clientEnv= */ ImmutableMap.of(),
/* topLevelFilesets= */ ImmutableMap.of(),
/* artifactExpander= */ null,
/* actionFileSystem= */ null,
/* skyframeDepsResult= */ null,
DiscoveredModulesPruner.DEFAULT,
SyscallCache.NO_CACHE,
ThreadStateReceiver.NULL_INSTANCE));
assertThat(actionResult.spawnResults()).isEmpty();
assertThat(spawnEnvironment.get("TEST")).isNotNull();
assertThat(spawnEnvironment).containsEntry("TEST", "TEST_VALUE");
}
@Test
public void testUpdateInputsNotPassedToShadowedAction() throws Exception {
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot out = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "out");
ArtifactRoot src = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/src")));
Artifact extraIn = ActionsTestUtil.createArtifact(src, scratch.file("/src/extra.in"));
Artifact discoveredIn = ActionsTestUtil.createArtifact(src, scratch.file("/src/discovered.in"));
Action shadowedAction = mock(Action.class);
when(shadowedAction.discoversInputs()).thenReturn(true);
when(shadowedAction.getInputs()).thenReturn(NestedSetBuilder.emptySet(Order.STABLE_ORDER));
when(shadowedAction.inputsKnown()).thenReturn(true);
when(shadowedAction.getOwner()).thenReturn(NULL_ACTION_OWNER);
when(shadowedAction.getRunfilesSupplier()).thenReturn(EmptyRunfilesSupplier.INSTANCE);
ExtraAction extraAction =
new ExtraAction(
NestedSetBuilder.create(Order.STABLE_ORDER, extraIn),
EmptyRunfilesSupplier.INSTANCE,
ImmutableSet.of(
(Artifact.DerivedArtifact)
ActionsTestUtil.createArtifact(out, scratch.file("/out/test.out"))),
shadowedAction,
false,
CommandLine.of(ImmutableList.of()),
ActionEnvironment.EMPTY,
ImmutableMap.of(),
"Executing extra action bla bla",
"bla bla");
extraAction.updateInputs(NestedSetBuilder.create(Order.STABLE_ORDER, extraIn, discoveredIn));
verify(shadowedAction, Mockito.never()).updateInputs(ArgumentMatchers.any());
}
}