/* * 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.jvm.java.JavaTest.COMPILED_TESTS_LIBRARY_FLAVOR; import static org.junit.Assert.assertEquals; import com.facebook.buck.android.AndroidBinaryBuilder; import com.facebook.buck.android.AndroidLibraryBuilder; import com.facebook.buck.jvm.java.JavaBinaryRuleBuilder; import com.facebook.buck.jvm.java.JavaLibraryBuilder; import com.facebook.buck.jvm.java.JavaTestBuilder; import com.facebook.buck.jvm.java.KeystoreBuilder; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.TargetNode; import com.facebook.buck.testutil.TargetGraphFactory; import com.facebook.buck.testutil.TestConsole; import com.facebook.buck.util.ObjectMappers; import com.facebook.buck.versions.VersionedAliasBuilder; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Sets; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.SortedSet; import org.junit.Before; import org.junit.Test; public class AuditClasspathCommandTest { private TestConsole console; private AuditClasspathCommand auditClasspathCommand; private CommandRunnerParams params; @Before public void setUp() throws IOException, InterruptedException { console = new TestConsole(); auditClasspathCommand = new AuditClasspathCommand(); params = CommandRunnerParamsForTesting.builder().setConsole(console).build(); } @Test public void testClassPathOutput() throws Exception { // Test that no output is created. auditClasspathCommand.printClasspath( params, TargetGraphFactory.newInstance(ImmutableSet.of()), ImmutableSet.of()); assertEquals("", console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); // Add build rules such that all implementations of HasClasspathEntries are tested. BuildTarget javaLibraryTarget = BuildTargetFactory.newInstance("//:test-java-library"); BuildTarget testJavaTarget = BuildTargetFactory.newInstance("//:project-tests"); BuildTarget androidLibraryTarget = BuildTargetFactory.newInstance("//:test-android-library"); BuildTarget keystoreTarget = BuildTargetFactory.newInstance("//:keystore"); BuildTarget testAndroidTarget = BuildTargetFactory.newInstance("//:test-android-binary"); TargetNode<?, ?> javaLibraryNode = JavaLibraryBuilder.createBuilder(javaLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .addTest(testJavaTarget) .build(); TargetNode<?, ?> androidLibraryNode = AndroidLibraryBuilder.createBuilder(androidLibraryTarget) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(javaLibraryTarget) .build(); TargetNode<?, ?> keystoreNode = KeystoreBuilder.createBuilder(keystoreTarget) .setStore(new FakeSourcePath("debug.keystore")) .setProperties(new FakeSourcePath("keystore.properties")) .build(); TargetNode<?, ?> testAndroidNode = AndroidBinaryBuilder.createBuilder(testAndroidTarget) .setManifest(new FakeSourcePath("AndroidManifest.xml")) .setKeystore(keystoreTarget) .setOriginalDeps(ImmutableSortedSet.of(androidLibraryTarget, javaLibraryTarget)) .build(); TargetNode<?, ?> testJavaNode = JavaTestBuilder.createBuilder(testJavaTarget) .addDep(javaLibraryTarget) .addSrc(Paths.get("src/com/facebook/test/ProjectTests.java")) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance( ImmutableSet.of( javaLibraryNode, androidLibraryNode, keystoreNode, testAndroidNode, testJavaNode)); auditClasspathCommand.printClasspath(params, targetGraph, ImmutableSet.of()); // Still empty. assertEquals("", console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); // Request the top build target. This will test the following: // - paths don't appear multiple times when dependencies are referenced multiple times. // - dependencies are walked // - independent targets in the same BUCK file are not included in the output auditClasspathCommand.printClasspath(params, targetGraph, ImmutableSet.of(testAndroidTarget)); Path root = javaLibraryTarget.getUnflavoredBuildTarget().getCellPath(); SortedSet<String> expectedPaths = Sets.newTreeSet( Arrays.asList( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), androidLibraryTarget, "lib__%s__output") .resolve(androidLibraryTarget.getShortName() + ".jar")) .toString(), root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaLibraryTarget, "lib__%s__output") .resolve(javaLibraryTarget.getShortName() + ".jar")) .toString())); String expectedClasspath = Joiner.on("\n").join(expectedPaths) + "\n"; assertEquals(expectedClasspath, console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); // Add independent test target. This will test: // - the union of the classpath is output. // - all rules have implemented HasClasspathEntries. // Note that the output streams are reset. setUp(); auditClasspathCommand.printClasspath( params, TargetGraphFactory.newInstance( ImmutableSet.of( javaLibraryNode, androidLibraryNode, keystoreNode, testAndroidNode, testJavaNode)), ImmutableSet.of( testAndroidTarget, javaLibraryTarget, androidLibraryTarget, testJavaTarget)); BuildTarget testJavaCompiledJar = testJavaTarget.withFlavors(COMPILED_TESTS_LIBRARY_FLAVOR); expectedPaths.add( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), testJavaCompiledJar, "lib__%s__output") .resolve(testJavaCompiledJar.getShortNameAndFlavorPostfix() + ".jar")) .toString()); expectedClasspath = Joiner.on("\n").join(expectedPaths) + "\n"; assertEquals(expectedClasspath, console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); } private static final String EXPECTED_JSON = Joiner.on("") .join( "{", "\"//:test-android-library\":", "[", "%s,", "%s", "],", "\"//:test-java-library\":", "[", "%s", "]", "}"); @Test public void testJsonClassPathOutput() throws Exception { // Build a DependencyGraph of build rules manually. BuildTarget javaTarget = BuildTargetFactory.newInstance("//:test-java-library"); TargetNode<?, ?> javaNode = JavaLibraryBuilder.createBuilder(javaTarget) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .build(); BuildTarget androidTarget = BuildTargetFactory.newInstance("//:test-android-library"); TargetNode<?, ?> androidNode = AndroidLibraryBuilder.createBuilder(androidTarget) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(javaTarget) .build(); auditClasspathCommand.printJsonClasspath( params, TargetGraphFactory.newInstance(ImmutableSet.of(androidNode, javaNode)), ImmutableSet.of(androidTarget, javaTarget)); Path root = javaTarget.getCellPath(); ObjectMapper objectMapper = ObjectMappers.legacyCreate(); String expected = String.format( EXPECTED_JSON, objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaTarget, "lib__%s__output") .resolve(javaTarget.getShortName() + ".jar"))), objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), androidTarget, "lib__%s__output") .resolve(androidTarget.getShortName() + ".jar"))), objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaTarget, "lib__%s__output") .resolve(javaTarget.getShortName() + ".jar")))); assertEquals(expected, console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); } @Test public void testClassPathWithVersions() throws Exception { // Build the test target graph. TargetNode<?, ?> javaLibrary = JavaLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:test-java-library")) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .build(); TargetNode<?, ?> androidLibrary = JavaLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:test-android-library")) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(javaLibrary.getBuildTarget()) .build(); TargetNode<?, ?> version = new VersionedAliasBuilder(BuildTargetFactory.newInstance("//:version")) .setVersions("1.0", "//:test-android-library") .build(); TargetNode<?, ?> binary = new JavaBinaryRuleBuilder(BuildTargetFactory.newInstance("//:rule")) .setDeps(ImmutableSortedSet.of(version.getBuildTarget())) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(javaLibrary, androidLibrary, version, binary); // Run the command. auditClasspathCommand.printClasspath( params.withBuckConfig( FakeBuckConfig.builder() .setSections(ImmutableMap.of("build", ImmutableMap.of("versions", "true"))) .build()), targetGraph, ImmutableSet.of(androidLibrary.getBuildTarget(), javaLibrary.getBuildTarget())); // Verify output. Path root = javaLibrary.getBuildTarget().getUnflavoredBuildTarget().getCellPath(); ImmutableSortedSet<String> expectedPaths = ImmutableSortedSet.of( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), androidLibrary.getBuildTarget(), "lib__%s__output") .resolve(androidLibrary.getBuildTarget().getShortName() + ".jar")) .toString(), root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaLibrary.getBuildTarget(), "lib__%s__output") .resolve(javaLibrary.getBuildTarget().getShortName() + ".jar")) .toString()); String expectedClasspath = Joiner.on("\n").join(expectedPaths) + "\n"; assertEquals(expectedClasspath, console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); } @Test public void testJsonClassPathWithVersions() throws Exception { // Build the test target graph. TargetNode<?, ?> javaLibrary = JavaLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:test-java-library")) .addSrc(Paths.get("src/com/facebook/TestJavaLibrary.java")) .build(); TargetNode<?, ?> androidLibrary = JavaLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:test-android-library")) .addSrc(Paths.get("src/com/facebook/TestAndroidLibrary.java")) .addDep(javaLibrary.getBuildTarget()) .build(); TargetNode<?, ?> version = new VersionedAliasBuilder(BuildTargetFactory.newInstance("//:version")) .setVersions("1.0", "//:test-android-library") .build(); TargetNode<?, ?> binary = new JavaBinaryRuleBuilder(BuildTargetFactory.newInstance("//:rule")) .setDeps(ImmutableSortedSet.of(version.getBuildTarget())) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(javaLibrary, androidLibrary, version, binary); // Run the command. auditClasspathCommand.printJsonClasspath( params.withBuckConfig( FakeBuckConfig.builder() .setSections(ImmutableMap.of("build", ImmutableMap.of("versions", "true"))) .build()), targetGraph, ImmutableSet.of(androidLibrary.getBuildTarget(), javaLibrary.getBuildTarget())); // Verify output. Path root = javaLibrary.getBuildTarget().getCellPath(); ObjectMapper objectMapper = ObjectMappers.legacyCreate(); String expected = String.format( EXPECTED_JSON, objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaLibrary.getBuildTarget(), "lib__%s__output") .resolve(javaLibrary.getBuildTarget().getShortName() + ".jar"))), objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), androidLibrary.getBuildTarget(), "lib__%s__output") .resolve(androidLibrary.getBuildTarget().getShortName() + ".jar"))), objectMapper.valueToTree( root.resolve( BuildTargets.getGenPath( params.getCell().getFilesystem(), javaLibrary.getBuildTarget(), "lib__%s__output") .resolve(javaLibrary.getBuildTarget().getShortName() + ".jar")))); assertEquals(expected, console.getTextWrittenToStdOut()); assertEquals("", console.getTextWrittenToStdErr()); } }