/*
* Copyright 2012-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.cli;
import static com.facebook.buck.rules.TestCellBuilder.createCellRoots;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.AbstractDescriptionArg;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.Cell;
import com.facebook.buck.rules.CellPathResolver;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.FakeBuildRule;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.TargetNode;
import com.facebook.buck.rules.TargetNodeFactory;
import com.facebook.buck.rules.TestCellBuilder;
import com.facebook.buck.rules.coercer.DefaultTypeCoercerFactory;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.util.RichStream;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.Hashing;
import java.io.IOException;
import java.nio.file.Path;
import org.junit.Before;
import org.junit.Test;
import org.kohsuke.args4j.CmdLineException;
/** Reports targets that own a specified list of files. */
public class OwnersReportTest {
public static class FakeRuleDescription implements Description<FakeRuleDescription.FakeArg> {
@Override
public Class<FakeArg> getConstructorArgType() {
return FakeArg.class;
}
@Override
public BuildRule createBuildRule(
TargetGraph targetGraph,
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots,
FakeArg args) {
return new FakeBuildRule(params, new SourcePathResolver(new SourcePathRuleFinder(resolver)));
}
public static class FakeArg extends AbstractDescriptionArg {
public ImmutableSet<Path> inputs;
}
}
private TargetNode<?, ?> createTargetNode(BuildTarget buildTarget, ImmutableSet<Path> inputs) {
Description<FakeRuleDescription.FakeArg> description = new FakeRuleDescription();
FakeRuleDescription.FakeArg arg = new FakeRuleDescription.FakeArg();
arg.inputs = inputs;
try {
return new TargetNodeFactory(new DefaultTypeCoercerFactory())
.create(
Hashing.sha1().hashString(buildTarget.getFullyQualifiedName(), UTF_8),
description,
arg,
filesystem,
buildTarget,
ImmutableSet.of(),
ImmutableSet.of(),
ImmutableSet.of(),
createCellRoots(filesystem));
} catch (NoSuchBuildTargetException e) {
throw new RuntimeException(e);
}
}
private ProjectFilesystem filesystem;
@Before
public void setUp() throws InterruptedException {
filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
}
@Test
public void verifyPathsThatAreNotFilesAreCorrectlyReported()
throws CmdLineException, IOException, InterruptedException {
filesystem.mkdirs(filesystem.getPath("java/somefolder/badfolder"));
filesystem.mkdirs(filesystem.getPath("com/test/subtest"));
// Inputs that should be treated as "non-files", i.e. as directories
ImmutableSet<String> inputs =
ImmutableSet.of("java/somefolder/badfolder", "java/somefolder", "com/test/subtest");
BuildTarget target = BuildTargetFactory.newInstance("//base:name");
TargetNode<?, ?> targetNode = createTargetNode(target, ImmutableSet.of());
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.generateOwnersReport(cell, targetNode, inputs);
assertTrue(report.owners.isEmpty());
assertTrue(report.nonExistentInputs.isEmpty());
assertTrue(report.inputsWithNoOwners.isEmpty());
assertEquals(inputs, report.nonFileInputs);
}
@Test
public void verifyMissingFilesAreCorrectlyReported()
throws CmdLineException, IOException, InterruptedException {
// Inputs that should be treated as missing files
ImmutableSet<String> inputs =
ImmutableSet.of(
"java/somefolder/badfolder/somefile.java",
"java/somefolder/perfect.java",
"com/test/subtest/random.java");
BuildTarget target = BuildTargetFactory.newInstance("//base:name");
TargetNode<?, ?> targetNode = createTargetNode(target, ImmutableSet.of());
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.generateOwnersReport(cell, targetNode, inputs);
assertTrue(report.owners.isEmpty());
assertTrue(report.nonFileInputs.isEmpty());
assertTrue(report.inputsWithNoOwners.isEmpty());
assertEquals(inputs, report.nonExistentInputs);
}
@Test
public void verifyInputsWithoutOwnersAreCorrectlyReported()
throws CmdLineException, IOException, InterruptedException {
// Inputs that should be treated as existing files
ImmutableSet<String> inputs =
ImmutableSet.of(
"java/somefolder/badfolder/somefile.java",
"java/somefolder/perfect.java",
"com/test/subtest/random.java");
ImmutableSet<Path> inputPaths =
RichStream.from(inputs).map(filesystem::getPath).toImmutableSet();
// Write dummy files.
for (Path path : inputPaths) {
filesystem.mkdirs(path.getParent());
filesystem.writeContentsToPath("", path);
}
BuildTarget target = BuildTargetFactory.newInstance("//base:name");
TargetNode<?, ?> targetNode = createTargetNode(target, ImmutableSet.of());
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.generateOwnersReport(cell, targetNode, inputs);
assertTrue(report.owners.isEmpty());
assertTrue(report.nonFileInputs.isEmpty());
assertTrue(report.nonExistentInputs.isEmpty());
assertEquals(inputPaths, report.inputsWithNoOwners);
}
@Test
public void verifyInputsAgainstRulesThatListDirectoryInputs()
throws IOException, InterruptedException {
// Inputs that should be treated as existing files
ImmutableSet<String> inputs =
ImmutableSet.of("java/somefolder/badfolder/somefile.java", "java/somefolder/perfect.java");
ImmutableSet<Path> inputPaths =
RichStream.from(inputs).map(filesystem::getPath).toImmutableSet();
for (Path path : inputPaths) {
filesystem.mkdirs(path.getParent());
filesystem.writeContentsToPath("", path);
}
BuildTarget target = BuildTargetFactory.newInstance("//base:name");
TargetNode<?, ?> targetNode =
createTargetNode(target, ImmutableSet.of(filesystem.getPath("java/somefolder")));
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.generateOwnersReport(cell, targetNode, inputs);
assertTrue(report.owners.containsKey(targetNode));
assertEquals(inputPaths, report.owners.get(targetNode));
assertTrue(report.nonFileInputs.isEmpty());
assertTrue(report.nonExistentInputs.isEmpty());
assertTrue(report.inputsWithNoOwners.isEmpty());
}
/** Verify that owners are correctly detected: - one owner, multiple inputs */
@Test
public void verifyInputsWithOneOwnerAreCorrectlyReported()
throws CmdLineException, IOException, InterruptedException {
ImmutableSet<String> inputs =
ImmutableSet.of(
"java/somefolder/badfolder/somefile.java",
"java/somefolder/perfect.java",
"com/test/subtest/random.java");
ImmutableSet<Path> inputPaths =
RichStream.from(inputs).map(filesystem::getPath).toImmutableSet();
for (Path path : inputPaths) {
filesystem.mkdirs(path.getParent());
filesystem.writeContentsToPath("", path);
}
BuildTarget target = BuildTargetFactory.newInstance("//base:name");
TargetNode<?, ?> targetNode = createTargetNode(target, inputPaths);
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.generateOwnersReport(cell, targetNode, inputs);
assertTrue(report.nonFileInputs.isEmpty());
assertTrue(report.nonExistentInputs.isEmpty());
assertTrue(report.inputsWithNoOwners.isEmpty());
assertEquals(inputs.size(), report.owners.size());
assertTrue(report.owners.containsKey(targetNode));
assertEquals(targetNode.getInputs(), report.owners.get(targetNode));
}
/** Verify that owners are correctly detected: - inputs that belong to multiple targets */
@Test
public void verifyInputsWithMultipleOwnersAreCorrectlyReported()
throws CmdLineException, IOException, InterruptedException {
ImmutableSet<String> inputs =
ImmutableSet.of(
"java/somefolder/badfolder/somefile.java",
"java/somefolder/perfect.java",
"com/test/subtest/random.java");
ImmutableSet<Path> inputPaths =
RichStream.from(inputs).map(filesystem::getPath).toImmutableSet();
for (Path path : inputPaths) {
filesystem.mkdirs(path.getParent());
filesystem.writeContentsToPath("", path);
}
BuildTarget target1 = BuildTargetFactory.newInstance("//base/name1:name");
BuildTarget target2 = BuildTargetFactory.newInstance("//base/name2:name");
TargetNode<?, ?> targetNode1 = createTargetNode(target1, inputPaths);
TargetNode<?, ?> targetNode2 = createTargetNode(target2, inputPaths);
Cell cell = new TestCellBuilder().setFilesystem(filesystem).build();
OwnersReport report = OwnersReport.emptyReport();
report = report.updatedWith(OwnersReport.generateOwnersReport(cell, targetNode1, inputs));
report = report.updatedWith(OwnersReport.generateOwnersReport(cell, targetNode2, inputs));
assertTrue(report.nonFileInputs.isEmpty());
assertTrue(report.nonExistentInputs.isEmpty());
assertTrue(report.inputsWithNoOwners.isEmpty());
assertTrue(report.owners.containsKey(targetNode1));
assertTrue(report.owners.containsKey(targetNode2));
assertEquals(targetNode1.getInputs(), report.owners.get(targetNode1));
assertEquals(targetNode2.getInputs(), report.owners.get(targetNode2));
}
}