/*
* Copyright 2014-present Facebook, Inc.
*
* 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.facebook.buck.rules;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import com.facebook.buck.event.BuckEventBus;
import com.facebook.buck.event.DefaultBuckEventBus;
import com.facebook.buck.graph.AcyclicDepthFirstPostOrderTraversal;
import com.facebook.buck.jvm.java.JavaLibraryBuilder;
import com.facebook.buck.model.BuildId;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.testutil.FakeFileHashCache;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.TargetGraphFactory;
import com.facebook.buck.timing.IncrementingFakeClock;
import com.facebook.buck.util.cache.FileHashCache;
import com.facebook.buck.util.cache.NullFileHashCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.HashCode;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import org.junit.Test;
public class TargetGraphHashingTest {
@Test
public void emptyTargetGraphHasEmptyHashes()
throws IOException, InterruptedException, AcyclicDepthFirstPostOrderTraversal.CycleException {
BuckEventBus eventBus = new DefaultBuckEventBus(new IncrementingFakeClock(), new BuildId());
TargetGraph targetGraph = TargetGraphFactory.newInstance();
assertThat(
new TargetGraphHashing(eventBus, targetGraph, new NullFileHashCache(), ImmutableList.of())
.hashTargetGraph()
.entrySet(),
empty());
}
@Test
public void hashChangesWhenSrcContentChanges()
throws IOException, InterruptedException, AcyclicDepthFirstPostOrderTraversal.CycleException {
FakeProjectFilesystem projectFilesystem = new FakeProjectFilesystem();
BuckEventBus eventBus = new DefaultBuckEventBus(new IncrementingFakeClock(), new BuildId());
TargetNode<?, ?> node =
createJavaLibraryTargetNodeWithSrcs(
BuildTargetFactory.newInstance("//foo:lib"),
HashCode.fromLong(64738),
ImmutableSet.of(Paths.get("foo/FooLib.java")));
TargetGraph targetGraph = TargetGraphFactory.newInstance(node);
FileHashCache baseCache =
new FakeFileHashCache(
ImmutableMap.of(
projectFilesystem.resolve("foo/FooLib.java"), HashCode.fromString("abcdef")));
FileHashCache modifiedCache =
new FakeFileHashCache(
ImmutableMap.of(
projectFilesystem.resolve("foo/FooLib.java"), HashCode.fromString("abc1ef")));
Map<BuildTarget, HashCode> baseResult =
new TargetGraphHashing(eventBus, targetGraph, baseCache, ImmutableList.of(node))
.hashTargetGraph();
Map<BuildTarget, HashCode> modifiedResult =
new TargetGraphHashing(eventBus, targetGraph, modifiedCache, ImmutableList.of(node))
.hashTargetGraph();
assertThat(baseResult, aMapWithSize(1));
assertThat(baseResult, hasKey(node.getBuildTarget()));
assertThat(modifiedResult, aMapWithSize(1));
assertThat(modifiedResult, hasKey(node.getBuildTarget()));
assertThat(
modifiedResult.get(node.getBuildTarget()),
not(equalTo(baseResult.get(node.getBuildTarget()))));
}
@Test
public void twoNodeIndependentRootsTargetGraphHasExpectedHashes()
throws IOException, InterruptedException, AcyclicDepthFirstPostOrderTraversal.CycleException {
FakeProjectFilesystem projectFilesystem = new FakeProjectFilesystem();
BuckEventBus eventBus = new DefaultBuckEventBus(new IncrementingFakeClock(), new BuildId());
TargetNode<?, ?> nodeA =
createJavaLibraryTargetNodeWithSrcs(
BuildTargetFactory.newInstance("//foo:lib"),
HashCode.fromLong(64738),
ImmutableSet.of(Paths.get("foo/FooLib.java")));
TargetNode<?, ?> nodeB =
createJavaLibraryTargetNodeWithSrcs(
BuildTargetFactory.newInstance("//bar:lib"),
HashCode.fromLong(49152),
ImmutableSet.of(Paths.get("bar/BarLib.java")));
TargetGraph targetGraphA = TargetGraphFactory.newInstance(nodeA);
TargetGraph targetGraphB = TargetGraphFactory.newInstance(nodeB);
TargetGraph commonTargetGraph = TargetGraphFactory.newInstance(nodeA, nodeB);
FileHashCache fileHashCache =
new FakeFileHashCache(
ImmutableMap.of(
projectFilesystem.resolve("foo/FooLib.java"), HashCode.fromString("abcdef"),
projectFilesystem.resolve("bar/BarLib.java"), HashCode.fromString("123456")));
Map<BuildTarget, HashCode> resultsA =
new TargetGraphHashing(eventBus, targetGraphA, fileHashCache, ImmutableList.of(nodeA))
.hashTargetGraph();
Map<BuildTarget, HashCode> resultsB =
new TargetGraphHashing(eventBus, targetGraphB, fileHashCache, ImmutableList.of(nodeB))
.hashTargetGraph();
Map<BuildTarget, HashCode> commonResults =
new TargetGraphHashing(
eventBus, commonTargetGraph, fileHashCache, ImmutableList.of(nodeA, nodeB))
.hashTargetGraph();
assertThat(resultsA, aMapWithSize(1));
assertThat(resultsA, hasKey(nodeA.getBuildTarget()));
assertThat(resultsB, aMapWithSize(1));
assertThat(resultsB, hasKey(nodeB.getBuildTarget()));
assertThat(commonResults, aMapWithSize(2));
assertThat(commonResults, hasKey(nodeA.getBuildTarget()));
assertThat(commonResults, hasKey(nodeB.getBuildTarget()));
assertThat(
resultsA.get(nodeA.getBuildTarget()), equalTo(commonResults.get(nodeA.getBuildTarget())));
assertThat(
resultsB.get(nodeB.getBuildTarget()), equalTo(commonResults.get(nodeB.getBuildTarget())));
}
private TargetGraph createGraphWithANodeAndADep(
BuildTarget nodeTarget, HashCode nodeHash, BuildTarget depTarget, HashCode depHash) {
TargetNode<?, ?> dep =
createJavaLibraryTargetNodeWithSrcs(
depTarget, depHash, ImmutableSet.of(Paths.get("dep/DepLib.java")));
TargetNode<?, ?> node =
createJavaLibraryTargetNodeWithSrcs(
nodeTarget, nodeHash, ImmutableSet.of(Paths.get("foo/FooLib.java")), dep);
return TargetGraphFactory.newInstance(node, dep);
}
@Test
public void hashChangesForDependentNodeWhenDepsChange()
throws IOException, InterruptedException, AcyclicDepthFirstPostOrderTraversal.CycleException {
FakeProjectFilesystem projectFilesystem = new FakeProjectFilesystem();
BuckEventBus eventBus = new DefaultBuckEventBus(new IncrementingFakeClock(), new BuildId());
BuildTarget nodeTarget = BuildTargetFactory.newInstance("//foo:lib");
BuildTarget depTarget = BuildTargetFactory.newInstance("//dep:lib");
TargetGraph targetGraphA =
createGraphWithANodeAndADep(
nodeTarget, HashCode.fromLong(12345), depTarget, HashCode.fromLong(64738));
TargetGraph targetGraphB =
createGraphWithANodeAndADep(
nodeTarget, HashCode.fromLong(12345), depTarget, HashCode.fromLong(84552));
FileHashCache fileHashCache =
new FakeFileHashCache(
ImmutableMap.of(
projectFilesystem.resolve("foo/FooLib.java"), HashCode.fromString("abcdef"),
projectFilesystem.resolve("dep/DepLib.java"), HashCode.fromString("123456")));
Map<BuildTarget, HashCode> resultA =
new TargetGraphHashing(
eventBus,
targetGraphA,
fileHashCache,
ImmutableList.of(targetGraphA.get(nodeTarget)))
.hashTargetGraph();
Map<BuildTarget, HashCode> resultB =
new TargetGraphHashing(
eventBus,
targetGraphB,
fileHashCache,
ImmutableList.of(targetGraphB.get(nodeTarget)))
.hashTargetGraph();
assertThat(resultA, aMapWithSize(2));
assertThat(resultA, hasKey(nodeTarget));
assertThat(resultA, hasKey(depTarget));
assertThat(resultB, aMapWithSize(2));
assertThat(resultB, hasKey(nodeTarget));
assertThat(resultB, hasKey(depTarget));
assertThat(resultA.get(nodeTarget), not(equalTo(resultB.get(nodeTarget))));
assertThat(resultA.get(depTarget), not(equalTo(resultB.get(depTarget))));
}
private static TargetNode<?, ?> createJavaLibraryTargetNodeWithSrcs(
BuildTarget buildTarget,
HashCode hashCode,
ImmutableSet<Path> srcs,
TargetNode<?, ?>... deps) {
JavaLibraryBuilder targetNodeBuilder = JavaLibraryBuilder.createBuilder(buildTarget, hashCode);
for (TargetNode<?, ?> dep : deps) {
targetNodeBuilder.addDep(dep.getBuildTarget());
}
for (Path src : srcs) {
targetNodeBuilder.addSrc(src);
}
return targetNodeBuilder.build();
}
}