blob: 1415a950d0b9b048c49ca3ad6e75c0ae82dfbf30 [file] [log] [blame]
// Copyright 2015 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.actions;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ACTION_OWNER;
import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.ActionExecutionContext.LostInputsCheck;
import com.google.devtools.build.lib.actions.ArtifactRoot.RootType;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.DummyExecutor;
import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
import com.google.devtools.build.lib.exec.SingleBuildFileCache;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationDepsUtils;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
import com.google.devtools.build.lib.testutil.Scratch;
import com.google.devtools.build.lib.testutil.TestFileOutErr;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
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 org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test cases for {@link SymlinkAction} when pointing to executables. */
@RunWith(JUnit4.class)
public class ExecutableSymlinkActionTest {
private Scratch scratch = new Scratch();
private Path execRoot;
private ArtifactRoot inputRoot;
private ArtifactRoot outputRoot;
TestFileOutErr outErr;
private Executor executor;
private final ActionKeyContext actionKeyContext = new ActionKeyContext();
@Before
public final void createExecutor() throws Exception {
final Path inputDir = scratch.dir("/in");
execRoot = scratch.getFileSystem().getPath("/");
inputRoot =
ArtifactRoot.asDerivedRoot(
execRoot, RootType.Output, inputDir.relativeTo(execRoot).getPathString());
String outSegment = "out";
execRoot.getChild(outSegment).createDirectoryAndParents();
outputRoot = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, outSegment);
outErr = new TestFileOutErr();
executor = new DummyExecutor(scratch.getFileSystem(), inputDir);
}
private ActionExecutionContext createContext() {
Path execRoot = executor.getExecRoot();
return new ActionExecutionContext(
executor,
new SingleBuildFileCache(
execRoot.getPathString(), execRoot.getFileSystem(), SyscallCache.NO_CACHE),
ActionInputPrefetcher.NONE,
actionKeyContext,
/*metadataHandler=*/ null,
/*rewindingEnabled=*/ false,
LostInputsCheck.NONE,
outErr,
/*eventHandler=*/ null,
/*clientEnv=*/ ImmutableMap.of(),
/*topLevelFilesets=*/ ImmutableMap.of(),
/*artifactExpander=*/ null,
/*actionFileSystem=*/ null,
/*skyframeDepsResult=*/ null,
DiscoveredModulesPruner.DEFAULT,
SyscallCache.NO_CACHE,
ThreadStateReceiver.NULL_INSTANCE);
}
@Test
public void testSimple() throws Exception {
Path inputFile = inputRoot.getRoot().getRelative("some-file");
Path outputFile = outputRoot.getRoot().getRelative("some-output");
FileSystemUtils.createEmptyFile(inputFile);
inputFile.setExecutable(/*executable=*/true);
Artifact input = ActionsTestUtil.createArtifact(inputRoot, inputFile);
Artifact output = ActionsTestUtil.createArtifact(outputRoot, outputFile);
SymlinkAction action = SymlinkAction.toExecutable(NULL_ACTION_OWNER, input, output, "progress");
ActionResult actionResult = action.execute(createContext());
assertThat(actionResult.spawnResults()).isEmpty();
assertThat(outputFile.resolveSymbolicLinks()).isEqualTo(inputFile);
}
@Test
public void testFailIfInputIsNotAFile() throws Exception {
Path dir = inputRoot.getRoot().getRelative("some-dir");
dir.createDirectoryAndParents();
Artifact input = ActionsTestUtil.createArtifact(inputRoot, dir);
Artifact output =
ActionsTestUtil.createArtifact(outputRoot, outputRoot.getRoot().getRelative("some-output"));
SymlinkAction action = SymlinkAction.toExecutable(NULL_ACTION_OWNER, input, output, "progress");
ActionExecutionException e =
assertThrows(ActionExecutionException.class, () -> action.execute(createContext()));
assertThat(e).hasMessageThat().contains("'in/some-dir' is not a file");
}
@Test
public void testFailIfInputIsNotExecutable() throws Exception {
Path file = inputRoot.getRoot().getRelative("some-file");
FileSystemUtils.createEmptyFile(file);
file.setExecutable(/*executable=*/false);
Artifact input = ActionsTestUtil.createArtifact(inputRoot, file);
Artifact output =
ActionsTestUtil.createArtifact(outputRoot, outputRoot.getRoot().getRelative("some-output"));
SymlinkAction action = SymlinkAction.toExecutable(NULL_ACTION_OWNER, input, output, "progress");
ActionExecutionException e =
assertThrows(ActionExecutionException.class, () -> action.execute(createContext()));
String want = "'in/some-file' is not executable";
String got = e.getMessage();
assertWithMessage(String.format("got %s, want %s", got, want))
.that(got.contains(want))
.isTrue();
}
@Test
public void testCodec() throws Exception {
Path file = inputRoot.getRoot().getRelative("some-file");
FileSystemUtils.createEmptyFile(file);
file.setExecutable(/*executable=*/ false);
Artifact.DerivedArtifact input =
(Artifact.DerivedArtifact) ActionsTestUtil.createArtifact(inputRoot, file);
input.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
Artifact.DerivedArtifact output =
(Artifact.DerivedArtifact)
ActionsTestUtil.createArtifact(
outputRoot, outputRoot.getRoot().getRelative("some-output"));
output.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
SymlinkAction action = SymlinkAction.toExecutable(NULL_ACTION_OWNER, input, output, "progress");
new SerializationTester(action)
.addDependency(FileSystem.class, scratch.getFileSystem())
.addDependency(
Root.RootCodecDependencies.class,
new Root.RootCodecDependencies(Root.absoluteRoot(scratch.getFileSystem())))
.addDependencies(SerializationDepsUtils.SERIALIZATION_DEPS_FOR_TEST)
.setVerificationFunction(
(in, out) -> {
SymlinkAction inAction = (SymlinkAction) in;
SymlinkAction outAction = (SymlinkAction) out;
assertThat(inAction.getPrimaryInput().getFilename())
.isEqualTo(outAction.getPrimaryInput().getFilename());
assertThat(inAction.getPrimaryOutput().getFilename())
.isEqualTo(outAction.getPrimaryOutput().getFilename());
assertThat(inAction.getOwner()).isEqualTo(outAction.getOwner());
assertThat(inAction.getProgressMessage()).isEqualTo(outAction.getProgressMessage());
})
.runTests();
}
}