blob: 66dd3b5d1edf938c6f8f47ee66b9da14c2ee84f3 [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 org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import com.google.common.collect.ImmutableClassToInstanceMap;
import com.google.common.collect.Lists;
import com.google.common.testing.EqualsTester;
import com.google.devtools.build.lib.actions.Artifact.ArchivedTreeArtifact;
import com.google.devtools.build.lib.actions.Artifact.SourceArtifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
import com.google.devtools.build.lib.actions.ArtifactResolver.ArtifactResolverSupplier;
import com.google.devtools.build.lib.actions.ArtifactRoot.RootType;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.LabelArtifactOwner;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelConstants;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.skyframe.serialization.AutoRegistry;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodecs;
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.util.FileType;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.skyframe.SkyFunctionName;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test for {@link Artifact} class. */
@RunWith(JUnit4.class)
public class ArtifactTest {
private Scratch scratch;
private Path execDir;
private ArtifactRoot rootDir;
private final ActionKeyContext actionKeyContext = new ActionKeyContext();
@Before
public final void setRootDir() throws Exception {
scratch = new Scratch();
execDir = scratch.dir("/base/exec");
rootDir = ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "root");
}
@Test
public void testConstruction_badRootDir() throws IOException {
Path f1 = scratch.file("/exec/dir/file.ext");
assertThrows(
IllegalArgumentException.class,
() ->
ActionsTestUtil.createArtifactWithExecPath(
ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "bogus"),
f1.relativeTo(execDir))
.getRootRelativePath());
}
private static long getUsedMemory() {
System.gc();
System.gc();
System.runFinalization();
System.gc();
System.gc();
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
@Test
public void testMemoryUsage() throws IOException {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
PathFragment aPath = PathFragment.create("src/a");
int arrSize = 1 << 20;
Object[] arr = new Object[arrSize];
long usedMemory = getUsedMemory();
for (int i = 0; i < arrSize; i++) {
arr[i] = ActionsTestUtil.createArtifactWithExecPath(root, aPath);
}
assertThat((getUsedMemory() - usedMemory) / arrSize).isAtMost(34L);
}
@Test
public void testEquivalenceRelation() throws Exception {
PathFragment aPath = PathFragment.create("src/a");
PathFragment bPath = PathFragment.create("src/b");
assertThat(ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, aPath))
.isEqualTo(ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, aPath));
assertThat(ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, bPath))
.isEqualTo(ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, bPath));
assertThat(
ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, aPath)
.equals(ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, bPath)))
.isFalse();
}
@Test
public void testComparison() {
PathFragment aPath = PathFragment.create("src/a");
PathFragment bPath = PathFragment.create("src/b");
Artifact aArtifact = ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, aPath);
Artifact bArtifact = ActionsTestUtil.createArtifactWithRootRelativePath(rootDir, bPath);
assertThat(Artifact.EXEC_PATH_COMPARATOR.compare(aArtifact, bArtifact)).isEqualTo(-1);
assertThat(Artifact.EXEC_PATH_COMPARATOR.compare(aArtifact, aArtifact)).isEqualTo(0);
assertThat(Artifact.EXEC_PATH_COMPARATOR.compare(bArtifact, bArtifact)).isEqualTo(0);
assertThat(Artifact.EXEC_PATH_COMPARATOR.compare(bArtifact, aArtifact)).isEqualTo(1);
}
@Test
public void testGetFilename() throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact javaFile = ActionsTestUtil.createArtifact(root, scratch.file("/foo/Bar.java"));
Artifact generatedHeader =
ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar.proto.h"));
Artifact generatedCc = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar.proto.cc"));
Artifact aCPlusPlusFile = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar.cc"));
assertThat(JavaSemantics.JAVA_SOURCE.matches(javaFile.getFilename())).isTrue();
assertThat(CppFileTypes.CPP_HEADER.matches(generatedHeader.getFilename())).isTrue();
assertThat(CppFileTypes.CPP_SOURCE.matches(generatedCc.getFilename())).isTrue();
assertThat(CppFileTypes.CPP_SOURCE.matches(aCPlusPlusFile.getFilename())).isTrue();
}
@Test
public void testGetExtension() throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact javaFile = ActionsTestUtil.createArtifact(root, scratch.file("/foo/Bar.java"));
assertThat(javaFile.getExtension()).isEqualTo("java");
}
@Test
public void testIsFileType() throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact javaFile = ActionsTestUtil.createArtifact(root, scratch.file("/foo/Bar.java"));
assertThat(javaFile.isFileType(FileType.of("java"))).isTrue();
assertThat(javaFile.isFileType(FileType.of("cc"))).isFalse();
}
@Test
public void testIsFileTypeSet() throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact javaFile = ActionsTestUtil.createArtifact(root, scratch.file("/foo/Bar.java"));
assertThat(javaFile.isFileType(FileTypeSet.of(FileType.of("cc"), FileType.of("java"))))
.isTrue();
assertThat(javaFile.isFileType(FileTypeSet.of(FileType.of("py"), FileType.of("js")))).isFalse();
assertThat(javaFile.isFileType(FileTypeSet.of())).isFalse();
}
@Test
public void testMangledPath() {
String path = "dir/sub_dir/name:end";
assertThat(Actions.escapedPath(path)).isEqualTo("dir_Ssub_Udir_Sname_Cend");
}
private List<Artifact> getFooBarArtifacts(MutableActionGraph actionGraph, boolean collapsedList)
throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact aHeader1 = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar1.h"));
Artifact aHeader2 = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar2.h"));
Artifact aHeader3 = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar3.h"));
ArtifactRoot middleRoot =
ArtifactRoot.asDerivedRoot(
scratch.dir("/foo"), RootType.Middleman, PathFragment.create("out"));
Artifact middleman = ActionsTestUtil.createArtifact(middleRoot, "middleman");
MiddlemanAction.create(
new ActionRegistry() {
@Override
public void registerAction(ActionAnalysisMetadata action) {
try {
actionGraph.registerAction(action);
} catch (ActionConflictException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Didn't expect interrupt in test", e);
}
}
@Override
public ActionLookupKey getOwner() {
throw new UnsupportedOperationException();
}
},
ActionsTestUtil.NULL_ACTION_OWNER,
NestedSetBuilder.create(Order.STABLE_ORDER, aHeader1, aHeader2, aHeader3),
middleman,
"desc",
MiddlemanType.AGGREGATING_MIDDLEMAN);
return collapsedList ? Lists.newArrayList(aHeader1, middleman) :
Lists.newArrayList(aHeader1, aHeader2, middleman);
}
@Test
public void testAddExecPaths() throws Exception {
List<String> paths = new ArrayList<>();
MutableActionGraph actionGraph = new MapBasedActionGraph(actionKeyContext);
Artifact.addExecPaths(getFooBarArtifacts(actionGraph, false), paths);
assertThat(paths).containsExactly("bar1.h", "bar2.h");
}
@Test
public void testAddExpandedArtifacts() throws Exception {
List<Artifact> expanded = new ArrayList<>();
MutableActionGraph actionGraph = new MapBasedActionGraph(actionKeyContext);
List<Artifact> original = getFooBarArtifacts(actionGraph, true);
Artifact.addExpandedArtifacts(original, expanded,
ActionInputHelper.actionGraphArtifactExpander(actionGraph));
List<Artifact> manuallyExpanded = new ArrayList<>();
for (Artifact artifact : original) {
ActionAnalysisMetadata action = actionGraph.getGeneratingAction(artifact);
if (artifact.isMiddlemanArtifact()) {
manuallyExpanded.addAll(action.getInputs().toList());
} else {
manuallyExpanded.add(artifact);
}
}
assertThat(expanded).containsExactlyElementsIn(manuallyExpanded);
}
@Test
public void testAddExecPathsNewActionGraph() throws Exception {
List<String> paths = new ArrayList<>();
MutableActionGraph actionGraph = new MapBasedActionGraph(actionKeyContext);
Artifact.addExecPaths(getFooBarArtifacts(actionGraph, false), paths);
assertThat(paths).containsExactly("bar1.h", "bar2.h");
}
@Test
public void testRootRelativePathIsSameAsExecPath() throws Exception {
ArtifactRoot root = ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo")));
Artifact a = ActionsTestUtil.createArtifact(root, scratch.file("/foo/bar1.h"));
assertThat(a.getRootRelativePath()).isSameInstanceAs(a.getExecPath());
}
@Test
public void testToDetailString() throws Exception {
Path execRoot = scratch.getFileSystem().getPath("/execroot/workspace");
Artifact a =
ActionsTestUtil.createArtifact(
ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "b"), "c");
assertThat(a.toDetailString()).isEqualTo("[[<execution_root>]b]c");
}
@Test
public void testWeirdArtifact() {
Path execRoot = scratch.getFileSystem().getPath("/");
assertThrows(
IllegalArgumentException.class,
() ->
ActionsTestUtil.createArtifactWithExecPath(
ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "a"),
PathFragment.create("c"))
.getRootRelativePath());
}
@Test
public void testCodec() throws Exception {
Artifact.DerivedArtifact artifact =
(Artifact.DerivedArtifact) ActionsTestUtil.createArtifact(rootDir, "src/a");
artifact.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
ArtifactRoot anotherRoot =
ArtifactRoot.asDerivedRoot(scratch.getFileSystem().getPath("/"), RootType.Output, "src");
Artifact.DerivedArtifact anotherArtifact =
new Artifact.DerivedArtifact(
anotherRoot,
anotherRoot.getExecPath().getRelative("src/c"),
ActionsTestUtil.NULL_ARTIFACT_OWNER);
anotherArtifact.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
new SerializationTester(artifact, anotherArtifact)
.addDependency(FileSystem.class, scratch.getFileSystem())
.addDependency(
Root.RootCodecDependencies.class, new Root.RootCodecDependencies(anotherRoot.getRoot()))
.addDependencies(SerializationDepsUtils.SERIALIZATION_DEPS_FOR_TEST)
.runTests();
}
@Test
public void testCodecRecyclesSourceArtifactInstances() throws Exception {
Root root = Root.fromPath(scratch.dir("/"));
ArtifactRoot artifactRoot = ArtifactRoot.asSourceRoot(root);
ArtifactFactory artifactFactory =
new ArtifactFactory(execDir.getParentDirectory(), "blaze-out");
ArtifactResolverSupplier artifactResolverSupplierForTest =
new ArtifactResolverSupplier() {
@Override
public Artifact.DerivedArtifact intern(Artifact.DerivedArtifact original) {
return original;
}
@Override
public ArtifactResolver get() {
return artifactFactory;
}
};
ObjectCodecs objectCodecs =
new ObjectCodecs(
AutoRegistry.get()
.getBuilder()
.addReferenceConstant(scratch.getFileSystem())
.setAllowDefaultCodec(true)
.build(),
ImmutableClassToInstanceMap.builder()
.put(FileSystem.class, scratch.getFileSystem())
.put(ArtifactResolverSupplier.class, artifactResolverSupplierForTest)
.put(
Root.RootCodecDependencies.class,
new Root.RootCodecDependencies(artifactRoot.getRoot()))
.build());
PathFragment pathFragment = PathFragment.create("src/foo.cc");
ArtifactOwner owner = new LabelArtifactOwner(Label.parseAbsoluteUnchecked("//foo:bar"));
SourceArtifact sourceArtifact = new SourceArtifact(artifactRoot, pathFragment, owner);
SourceArtifact deserialized1 =
(SourceArtifact) objectCodecs.deserialize(objectCodecs.serialize(sourceArtifact));
SourceArtifact deserialized2 =
(SourceArtifact) objectCodecs.deserialize(objectCodecs.serialize(sourceArtifact));
assertThat(deserialized1).isSameInstanceAs(deserialized2);
Artifact sourceArtifactFromFactory =
artifactFactory.getSourceArtifact(pathFragment, root, owner);
Artifact deserialized =
(Artifact) objectCodecs.deserialize(objectCodecs.serialize(sourceArtifactFromFactory));
assertThat(sourceArtifactFromFactory).isSameInstanceAs(deserialized);
}
@Test
public void testLongDirname() throws Exception {
String dirName = createDirNameArtifact().getDirname();
assertThat(dirName).isEqualTo("aaa/bbb/ccc");
}
@Test
public void testDirnameInExecutionDir() throws Exception {
Artifact artifact =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/foo"))),
scratch.file("/foo/bar.txt"));
assertThat(artifact.getDirname()).isEqualTo(".");
}
@Test
public void testCanConstructPathFromDirAndFilename() throws Exception {
Artifact artifact = createDirNameArtifact();
String constructed =
String.format("%s/%s", artifact.getDirname(), artifact.getFilename());
assertThat(constructed).isEqualTo("aaa/bbb/ccc/ddd");
}
@Test
public void testIsSourceArtifact() throws Exception {
assertThat(
new Artifact.SourceArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/"))),
PathFragment.create("src/foo.cc"),
ArtifactOwner.NULL_OWNER)
.isSourceArtifact())
.isTrue();
assertThat(
ActionsTestUtil.createArtifact(
ArtifactRoot.asDerivedRoot(scratch.dir("/genfiles"), RootType.Output, "aaa"),
scratch.file("/genfiles/aaa/bar.out"))
.isSourceArtifact())
.isFalse();
}
@Test
public void testGetRoot() throws Exception {
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot root = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "newRoot");
assertThat(ActionsTestUtil.createArtifact(root, scratch.file("/newRoot/foo")).getRoot())
.isEqualTo(root);
}
@Test
public void hashCodeAndEquals() {
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot root = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "newRoot");
ActionLookupKey firstOwner =
new ActionLookupKey() {
@Override
public Label getLabel() {
return null;
}
@Override
public SkyFunctionName functionName() {
return null;
}
};
ActionLookupKey secondOwner =
new ActionLookupKey() {
@Override
public Label getLabel() {
return null;
}
@Override
public SkyFunctionName functionName() {
return null;
}
};
Artifact.DerivedArtifact derived1 =
new Artifact.DerivedArtifact(root, PathFragment.create("newRoot/shared"), firstOwner);
derived1.setGeneratingActionKey(ActionLookupData.create(firstOwner, 0));
Artifact.DerivedArtifact derived2 =
new Artifact.DerivedArtifact(root, PathFragment.create("newRoot/shared"), secondOwner);
derived2.setGeneratingActionKey(ActionLookupData.create(secondOwner, 0));
ArtifactRoot sourceRoot = ArtifactRoot.asSourceRoot(Root.fromPath(root.getRoot().asPath()));
Artifact source1 = new SourceArtifact(sourceRoot, PathFragment.create("shared"), firstOwner);
Artifact source2 = new SourceArtifact(sourceRoot, PathFragment.create("shared"), secondOwner);
new EqualsTester()
.addEqualityGroup(derived1)
.addEqualityGroup(derived2)
.addEqualityGroup(source1, source2)
.testEquals();
assertThat(derived1.hashCode()).isEqualTo(derived2.hashCode());
assertThat(derived1.hashCode()).isNotEqualTo(source1.hashCode());
assertThat(source1.hashCode()).isEqualTo(source2.hashCode());
Artifact.OwnerlessArtifactWrapper wrapper1 = new Artifact.OwnerlessArtifactWrapper(derived1);
Artifact.OwnerlessArtifactWrapper wrapper2 = new Artifact.OwnerlessArtifactWrapper(derived2);
Artifact.OwnerlessArtifactWrapper wrapper3 = new Artifact.OwnerlessArtifactWrapper(source1);
Artifact.OwnerlessArtifactWrapper wrapper4 = new Artifact.OwnerlessArtifactWrapper(source2);
new EqualsTester()
.addEqualityGroup(wrapper1, wrapper2)
.addEqualityGroup(wrapper3, wrapper4)
.testEquals();
Path path1 = derived1.getPath();
Path path2 = derived2.getPath();
Path path3 = source1.getPath();
Path path4 = source2.getPath();
new EqualsTester().addEqualityGroup(path1, path2, path3, path4).testEquals();
}
private Artifact createDirNameArtifact() throws Exception {
return ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(scratch.dir("/"))),
scratch.file("/aaa/bbb/ccc/ddd"));
}
@Test
public void canDeclareContentBasedOutput() {
Path execRoot = scratch.getFileSystem().getPath("/");
ArtifactRoot root = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "newRoot");
assertThat(
new Artifact.DerivedArtifact(
root,
PathFragment.create("newRoot/my.output"),
ActionsTestUtil.NULL_ARTIFACT_OWNER,
/*contentBasedPath=*/ true)
.contentBasedPath())
.isTrue();
}
@Test
public void testGetRepositoryRelativePathExternalSourceArtifacts() throws IOException {
ArtifactRoot externalRoot =
ArtifactRoot.asExternalSourceRoot(
Root.fromPath(
scratch
.dir("/output_base")
.getRelative(LabelConstants.EXTERNAL_REPOSITORY_LOCATION)
.getRelative("foo")));
// --experimental_sibling_repository_layout not set
assertThat(
new Artifact.SourceArtifact(
externalRoot,
LabelConstants.EXTERNAL_PATH_PREFIX.getRelative("foo/bar/baz.cc"),
ArtifactOwner.NULL_OWNER)
.getRepositoryRelativePath())
.isEqualTo(PathFragment.create("bar/baz.cc"));
// --experimental_sibling_repository_layout set
assertThat(
new Artifact.SourceArtifact(
externalRoot,
LabelConstants.EXPERIMENTAL_EXTERNAL_PATH_PREFIX.getRelative("foo/bar/baz.cc"),
ArtifactOwner.NULL_OWNER)
.getRepositoryRelativePath())
.isEqualTo(PathFragment.create("bar/baz.cc"));
}
@Test
public void archivedTreeArtifact_create_returnsArtifactInArchivedRoot() {
ArtifactRoot root =
ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "blaze-out", "fastbuild");
SpecialArtifact tree = createTreeArtifact(root, "tree");
ArchivedTreeArtifact archivedTreeArtifact =
ArchivedTreeArtifact.create(tree, PathFragment.create("blaze-out"));
assertThat(archivedTreeArtifact.getParent()).isSameInstanceAs(tree);
assertThat(archivedTreeArtifact.getArtifactOwner())
.isSameInstanceAs(ActionsTestUtil.NULL_ARTIFACT_OWNER);
assertThat(archivedTreeArtifact.getExecPathString())
.isEqualTo("blaze-out/:archived_tree_artifacts/fastbuild/tree.zip");
assertThat(archivedTreeArtifact.getRoot().getExecPathString())
.isEqualTo("blaze-out/:archived_tree_artifacts/fastbuild");
}
@Test
public void archivedTreeArtifact_create_returnsArtifactWithGeneratingActionFromParent() {
ActionLookupKey actionLookupKey = mock(ActionLookupKey.class);
ActionLookupData actionLookupData = ActionLookupData.create(actionLookupKey, 0);
SpecialArtifact tree = createTreeArtifact(rootDir, "tree", actionLookupData);
ArchivedTreeArtifact archivedTreeArtifact =
ArchivedTreeArtifact.create(tree, PathFragment.create("root"));
assertThat(archivedTreeArtifact.getExecPathString())
.isEqualTo("root/:archived_tree_artifacts/tree.zip");
assertThat(archivedTreeArtifact.getArtifactOwner()).isSameInstanceAs(actionLookupKey);
assertThat(archivedTreeArtifact.getGeneratingActionKey()).isSameInstanceAs(actionLookupData);
}
@Test
public void archivedTreeArtifact_createWithLongerDerivedPrefix_returnsArtifactWithCorrectPath() {
ArtifactRoot root =
ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "dir1", "dir2", "dir3");
SpecialArtifact tree = createTreeArtifact(root, "tree");
ArchivedTreeArtifact archivedTreeArtifact =
ArchivedTreeArtifact.create(tree, PathFragment.create("dir1/dir2"));
assertThat(archivedTreeArtifact.getExecPathString())
.isEqualTo("dir1/dir2/:archived_tree_artifacts/dir3/tree.zip");
assertThat(archivedTreeArtifact.getRoot().getExecPathString())
.isEqualTo("dir1/dir2/:archived_tree_artifacts/dir3");
}
@Test
public void archivedTreeArtifact_create_failsForWrongDerivedPrefix() {
ArtifactRoot root =
ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "blaze-out", "fastbuild");
SpecialArtifact tree = createTreeArtifact(root, "tree");
PathFragment wrongPrefix = PathFragment.create("notAPrefix");
assertThrows(
IllegalArgumentException.class, () -> ArchivedTreeArtifact.create(tree, wrongPrefix));
}
@Test
public void archivedTreeArtifact_create_failsForDerivedPrefixOutsideOfArtifactRoot() {
ArtifactRoot root = ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "dir1", "dir2");
SpecialArtifact tree = createTreeArtifact(root, "dir3/tree");
PathFragment prefixOutsideOfRoot = PathFragment.create("dir1/dir2/dir3");
assertThrows(
IllegalArgumentException.class,
() -> ArchivedTreeArtifact.create(tree, prefixOutsideOfRoot));
}
@Test
public void archivedTreeArtifact_createWithCustomDerivedTreeRoot_returnsArtifactWithCustomRoot() {
ArtifactRoot root =
ArtifactRoot.asDerivedRoot(execDir, RootType.Output, "blaze-out", "fastbuild");
SpecialArtifact tree = createTreeArtifact(root, "dir/tree");
ArchivedTreeArtifact archivedTreeArtifact =
ArchivedTreeArtifact.createWithCustomDerivedTreeRoot(
tree,
PathFragment.create("blaze-out"),
PathFragment.create("custom/custom2"),
PathFragment.create("treePath/file.xyz"));
assertThat(archivedTreeArtifact.getParent()).isSameInstanceAs(tree);
assertThat(archivedTreeArtifact.getExecPathString())
.isEqualTo("blaze-out/custom/custom2/fastbuild/treePath/file.xyz");
assertThat(archivedTreeArtifact.getRoot().getExecPathString())
.isEqualTo("blaze-out/custom/custom2/fastbuild");
}
@Test
public void archivedTreeArtifact_codec_roundTripsArchivedArtifact() throws Exception {
ArchivedTreeArtifact artifact1 = createArchivedTreeArtifact(rootDir, "tree1");
ArtifactRoot anotherRoot =
ArtifactRoot.asDerivedRoot(scratch.getFileSystem().getPath("/"), RootType.Output, "src");
ArchivedTreeArtifact artifact2 = createArchivedTreeArtifact(anotherRoot, "tree2");
new SerializationTester(artifact1, artifact2)
.addDependency(FileSystem.class, scratch.getFileSystem())
.addDependency(
Root.RootCodecDependencies.class, new Root.RootCodecDependencies(anotherRoot.getRoot()))
.addDependencies(SerializationDepsUtils.SERIALIZATION_DEPS_FOR_TEST)
.<ArchivedTreeArtifact>setVerificationFunction(
(original, deserialized) -> {
assertThat(original).isEqualTo(deserialized);
assertThat(original.getGeneratingActionKey())
.isEqualTo(deserialized.getGeneratingActionKey());
})
.runTests();
}
@Test
public void archivedTreeArtifact_getExecPathWithinArchivedArtifactsTree_returnsCorrectPath() {
assertThat(
ArchivedTreeArtifact.getExecPathWithinArchivedArtifactsTree(
PathFragment.create("bazel-out"),
PathFragment.create("bazel-out/k8-fastbuild/bin/dir/subdir")))
.isEqualTo(
PathFragment.create("bazel-out/:archived_tree_artifacts/k8-fastbuild/bin/dir/subdir"));
}
@Test
public void archivedTreeArtifact_getExecPathWithinArchivedArtifactsTree_wrongPrefix_fails() {
assertThrows(
IllegalArgumentException.class,
() ->
ArchivedTreeArtifact.getExecPathWithinArchivedArtifactsTree(
PathFragment.create("wrongPrefix"),
PathFragment.create("bazel-out/k8-fastbuild/bin/dir/subdir")));
}
private static SpecialArtifact createTreeArtifact(ArtifactRoot root, String relativePath) {
return createTreeArtifact(root, relativePath, ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
}
private static SpecialArtifact createTreeArtifact(
ArtifactRoot root, String relativePath, ActionLookupData actionLookupData) {
SpecialArtifact treeArtifact =
new SpecialArtifact(
root,
root.getExecPath().getRelative(relativePath),
actionLookupData.getActionLookupKey(),
SpecialArtifactType.TREE);
treeArtifact.setGeneratingActionKey(actionLookupData);
return treeArtifact;
}
private static ArchivedTreeArtifact createArchivedTreeArtifact(
ArtifactRoot root, String treeRelativePath) {
return ArchivedTreeArtifact.create(
createTreeArtifact(root, treeRelativePath), root.getExecPath().subFragment(0, 1));
}
}