blob: 99d577789e655613465112368b364d9c9e18e13f [file] [log] [blame]
// Copyright 2016 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.analysis;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.testing.EqualsTester;
import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.packages.License;
import com.google.devtools.build.lib.packages.License.DistributionType;
import com.google.devtools.build.lib.packages.License.LicenseParsingException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Integration tests for {@link License}.
*/
@RunWith(JUnit4.class)
public class LicensingTests extends BuildViewTestCase {
/** Filter to remove implicit dependencies of sh_* rules. */
private static final Predicate<String> SH_LABEL_NAME_FILTER = new Predicate<String>() {
@Override
public boolean apply(String label) {
return !label.startsWith("//util/shell/");
}
};
private static final Predicate<Label> SH_LABEL_FILTER = new Predicate<Label>() {
@Override
public boolean apply(Label label) {
return SH_LABEL_NAME_FILTER.apply("//" + label.getPackageName());
}
};
/** Filter to remove implicit dependencies of Java rules. */
private static final Predicate<String> JAVA_LABEL_NAME_FILTER = new Predicate<String>() {
@Override
public boolean apply(String label) {
return !label.startsWith("//third_party/java/jdk");
}
};
public static final Predicate<Label> JAVA_LABEL_FILTER = new Predicate<Label>() {
@Override
public boolean apply(Label label) {
return JAVA_LABEL_NAME_FILTER.apply("//" + label.getPackageName());
}
};
@SuppressWarnings("unchecked")
public static final Predicate<Label> CC_OR_JAVA_OR_SH_LABEL_FILTER =
Predicates.and(
AnalysisMock.get().ccSupport().labelFilter(),
JAVA_LABEL_FILTER,
SH_LABEL_FILTER);
@Before
public final void useCorrectConfiguration() throws Exception {
useConfiguration("--check_licenses");
}
@Test
public void testCollectDistribs() throws Exception {
scratch.file("a/BUILD",
"distribs(['client', 'web'])",
"cc_library(name = 'alib', srcs=['a.cc'], deps=[':blib'])",
"cc_library(name = 'blib', distribs=['client'])");
scratch.file("kaboom/BUILD",
"cc_library(name = 'boom', srcs=['bang.cc'])");
assertThat(getTarget("//a:alib").getDistributions())
.containsExactlyElementsIn(
Sets.newHashSet(License.DistributionType.CLIENT, License.DistributionType.WEB));
assertThat(getTarget("//a:blib").getDistributions())
.containsExactlyElementsIn(Sets.newHashSet(License.DistributionType.CLIENT));
assertThat(getTarget("//kaboom:boom").getDistributions())
.containsExactlyElementsIn(Sets.newHashSet(License.DistributionType.INTERNAL));
}
// Same test, using package.distribs.
@Test
public void testCollectDistribsPackage() throws Exception {
scratch.file("a/BUILD",
"package(distribs = ['client', 'web'])",
"cc_library(name = 'alib', srcs=['a.cc'], deps=[':blib'])",
"cc_library(name = 'blib', distribs=['client'])");
scratch.file("kaboom/BUILD",
"cc_library(name = 'boom', srcs=['bang.cc'])");
assertThat(getTarget("//a:alib").getDistributions())
.containsExactlyElementsIn(
Sets.newHashSet(License.DistributionType.CLIENT, License.DistributionType.WEB));
assertThat(getTarget("//a:blib").getDistributions())
.containsExactlyElementsIn(Sets.newHashSet(License.DistributionType.CLIENT));
assertThat(getTarget("//kaboom:boom").getDistributions())
.containsExactlyElementsIn(Sets.newHashSet(License.DistributionType.INTERNAL));
}
// Test for package.licenses
@Test
public void testCollectLicensesPackage() throws Exception {
scratch.file("a/BUILD",
"licenses(['restricted', 'reciprocal'])",
"exports_files(['a'])");
ConfiguredTarget target = getConfiguredTarget("//a:a");
License license = getTarget(target.getLabel()).getLicense();
assertThat(license).isEqualTo(License.parseLicense(Arrays.asList("restricted", "reciprocal")));
}
@Test
public void testCollectLicenses() throws Exception {
Predicate<Label> SOURCE_FILTER =
new Predicate<Label>() {
@Override
public boolean apply(Label label) {
// Remove source files from the results.
return AnalysisMock.get().ccSupport().labelFilter().apply(label)
&& !label.toString().endsWith(".cc");
}
};
scratch.file("a/BUILD",
"licenses(['restricted', 'reciprocal'])",
"cc_library(name = 'alib', srcs=['a.cc'], deps=[':blib'])",
"cc_library(name = 'blib', srcs=['b.cc'], distribs=['web'], "
+ "deps=['//kaboom:boom', '//kablam:blam'])",
"exports_files(['c'])");
scratch.file("kaboom/BUILD",
"licenses(['notice'])",
"cc_library(name = 'boom', srcs=['bang.cc'])");
scratch.file("kablam/BUILD",
"licenses(['restricted','exception=//a:alib'])",
"cc_library(name='blam', srcs=['blam.cc'])");
ConfiguredTarget aTarget = getConfiguredTarget("//a:alib");
ConfiguredTarget bTarget = getConfiguredTarget("//a:blib");
ConfiguredTarget cTarget = getConfiguredTarget("//a:c");
ConfiguredTarget kaboomTarget = getConfiguredTarget("//kaboom:boom");
ConfiguredTarget kablamTarget = getConfiguredTarget("//kablam:blam");
Map<Label, License> aMap =
Maps.filterKeys(getTransitiveLicenses(aTarget), SOURCE_FILTER);
Map<Label, License> aExpected = licenses("//a:alib", "restricted,reciprocal",
"//a:blib", "restricted,reciprocal",
"//kablam:blam", "restricted,exception=//a:alib",
"//kaboom:boom", "notice");
assertSameMapEntries(aExpected, aMap);
Map<Label, License> bMap =
Maps.filterKeys(getTransitiveLicenses(bTarget), SOURCE_FILTER);
Map<Label, License> bExpected = licenses("//a:blib", "restricted,reciprocal",
"//kablam:blam", "restricted,exception=//a:alib",
"//kaboom:boom", "notice");
assertSameMapEntries(bExpected, bMap);
Map<Label, License> kaboomMap =
Maps.filterKeys(getTransitiveLicenses(kaboomTarget), SOURCE_FILTER);
assertSameMapEntries(
licenses("//kaboom:boom", "notice"),
kaboomMap);
Map<Label, License> kablamMap =
Maps.filterKeys(getTransitiveLicenses(kablamTarget), SOURCE_FILTER);
assertSameMapEntries(
licenses("//kablam:blam", "restricted,exception=//a:alib"),
kablamMap);
License cLicense = getTarget(cTarget.getLabel()).getLicense();
assertThat(cLicense).isEqualTo(License.parseLicense(Arrays.asList("restricted", "reciprocal")));
}
@Test
public void testClientLicenseOverridesDefault() throws Exception {
scratch.file("a/BUILD",
"licenses(['restricted', 'reciprocal'])",
"cc_library(name = 'alib', srcs=['a.cc'], deps=[':blib'], licenses=['unencumbered'])",
"cc_library(name = 'blib', srcs=['b.cc'], distribs=['web'])",
"exports_files(['c'], licenses = ['unencumbered'])");
ConfiguredTarget aTarget = getConfiguredTarget("//a:alib");
ConfiguredTarget bTarget = getConfiguredTarget("//a:blib");
ConfiguredTarget cTarget = getConfiguredTarget("//a:c");
License aLicense = getTarget(aTarget.getLabel()).getLicense();
License bLicense = getTarget(bTarget.getLabel()).getLicense();
License cLicense = getTarget(cTarget.getLabel()).getLicense();
assertThat(aLicense.equals(bLicense)).isFalse();
assertThat(aLicense).isEqualTo(License.parseLicense(Arrays.asList("unencumbered")));
assertThat(bLicense).isEqualTo(License.parseLicense(Arrays.asList("restricted", "reciprocal")));
assertThat(cLicense).isEqualTo(License.parseLicense(Arrays.asList("unencumbered")));
}
@Test
public void testNoneLicenseHandledCorrectly() throws Exception {
scratch.file("music/BUILD",
"sh_binary(name='piano', srcs=['piano.sh'], licenses=['none'])");
Map<Label, License> licenses = Maps.filterKeys(
getTransitiveLicenses(getConfiguredTarget("//music:piano")),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
assertThat(licenses).isEmpty();
}
@Test
public void testToolLicenseAddedCorrectly() throws Exception {
scratch.file("powertools/BUILD",
"sh_binary(name = 'chainsaw',",
" srcs = ['chainsaw.sh'],",
" licenses=['restricted'],",
" output_licenses=['unencumbered'])");
scratch.file("gr/BUILD",
"licenses(['unencumbered'])",
"genrule(name = 'lumberjack',",
" outs=['firewood'],",
" tools=['//powertools:chainsaw'],",
" cmd='')",
"genrule(name = 'xorn',",
" outs=['jewel'],",
" srcs=['//powertools:chainsaw'],",
" cmd='')");
ConfiguredTarget lumberjack = getConfiguredTarget("//gr:lumberjack");
ConfiguredTarget xorn = getConfiguredTarget("//gr:xorn");
Map<Label, License> lumberjackActual = Maps.filterKeys(getTransitiveLicenses(lumberjack),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> xornActual = Maps.filterKeys(getTransitiveLicenses(xorn),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> lumberjackExpected = licenses(
"//powertools:chainsaw", "unencumbered",
"//gr:lumberjack", "unencumbered");
Map<Label, License> xornExpected = licenses(
"//powertools:chainsaw", "restricted",
"//gr:xorn", "unencumbered");
assertSameMapEntries(lumberjackExpected, lumberjackActual);
assertSameMapEntries(xornExpected, xornActual);
}
@Test
public void testToolLicenseDoesNotIncludeDependencies() throws Exception {
scratch.file("powertools/BUILD",
"sh_binary(name = 'chainsaw',",
" srcs = ['chainsaw.sh'],",
" deps = [':gasoline'],",
" licenses = ['restricted'],",
" output_licenses=['unencumbered'])",
"sh_binary(name = 'gasoline',",
" srcs = ['gasoline.sh'],",
" licenses = ['notice'])");
scratch.file("gr/BUILD",
"licenses(['unencumbered'])",
"genrule(name = 'lumberjack',",
" outs=['firewood'],",
" tools=['//powertools:chainsaw'],",
" cmd='')");
ConfiguredTarget lumberjack = getConfiguredTarget("//gr:lumberjack");
Map<Label, License> actual = Maps.filterKeys(getTransitiveLicenses(lumberjack),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses(
"//powertools:chainsaw", "unencumbered",
"//gr:lumberjack", "unencumbered");
assertSameMapEntries(expected, actual);
}
@Test
public void testFilegroupAllowsOutputLicenseDeclaration() throws Exception {
scratch.file("apple/BUILD",
"licenses(['restricted'])",
"filegroup(name='apples',",
" output_licenses=['unencumbered'],",
" srcs=['rambo', 'granny_smith'])");
scratch.file("apfelmuss/BUILD",
"licenses(['unencumbered'])",
"genrule(name = 'apfelmuss',",
" outs = ['jar'],",
" tools = ['//apple:apples'],",
" cmd = 'magic')");
ConfiguredTarget apfelmuss = getConfiguredTarget("//apfelmuss:apfelmuss");
Map<Label, License> actual = Maps.filterKeys(getTransitiveLicenses(apfelmuss),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses(
"//apfelmuss:apfelmuss", "unencumbered",
"//apple:apples", "unencumbered");
assertSameMapEntries(expected, actual);
}
@Test
public void testEmptyToolLicenseWorks() throws Exception {
scratch.file("powertools/BUILD",
"sh_binary(name = 'chainsaw',",
" srcs = ['chainsaw.sh'],",
" deps = [':gasoline'],",
" licenses = ['restricted'],",
" output_licenses=[])",
"sh_binary(name = 'gasoline',",
" srcs = ['gasoline.sh'],",
" licenses = ['notice'])");
scratch.file("gr/BUILD",
"genrule(name = 'lumberjack',",
" outs=['firewood'],",
" tools=['//powertools:chainsaw'],",
" cmd='')");
ConfiguredTarget lumberjack = getConfiguredTarget("//gr:lumberjack");
Map<Label, License> actual = Maps.filterKeys(getTransitiveLicenses(lumberjack),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses("//powertools:chainsaw", "");
assertSameMapEntries(expected, actual);
}
@Test
public void testToolLicenseIncludesDependenciesIfNoOutputLicense() throws Exception {
scratch.file("powertools/BUILD",
"sh_binary(name = 'chainsaw',",
" srcs = ['chainsaw.sh'],",
" deps = [':gasoline'],",
" licenses = ['restricted'])",
"sh_binary(name = 'gasoline',",
" srcs = ['gasoline.sh'],",
" licenses = ['notice'])");
scratch.file("gr/BUILD",
"licenses(['unencumbered'])",
"genrule(name = 'lumberjack',",
" outs=['firewood'],",
" tools=['//powertools:chainsaw'],",
" cmd='')");
ConfiguredTarget lumberjack = getConfiguredTarget("//gr:lumberjack");
Map<Label, License> actual = Maps.filterKeys(getTransitiveLicenses(lumberjack),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses(
"//powertools:chainsaw", "restricted",
"//powertools:gasoline", "notice",
"//gr:lumberjack", "unencumbered");
assertSameMapEntries(expected, actual);
}
@Test
public void testToolLicenseRecursively() throws Exception {
scratch.file("powertools/BUILD",
"licenses(['restricted'])",
"filegroup(name = 'chainsaw',",
" srcs = ['chainsaw.sh'],",
" licenses=['restricted'],",
" output_licenses=['unencumbered'])",
"filegroup(name = 'forward',",
" srcs = [':chainsaw'])");
scratch.file("gr/BUILD",
"licenses(['unencumbered'])",
"genrule(name = 'lumberjack',",
" outs=['firewood'],",
" tools=['//powertools:forward'],",
" cmd='')");
ConfiguredTarget lumberjack = getConfiguredTarget("//gr:lumberjack");
Map<Label, License> lumberjackActual = Maps.filterKeys(getTransitiveLicenses(lumberjack),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> lumberjackExpected = licenses(
"//powertools:chainsaw", "unencumbered",
"//powertools:forward", "restricted",
"//gr:lumberjack", "unencumbered");
assertSameMapEntries(lumberjackExpected, lumberjackActual);
}
@Test
public void testHostAttributeCanBeTool() throws Exception {
scratch.file(
"test/BUILD",
"genrule(",
" name='gen',",
" outs=['hello.txt'],",
" cmd='exit 1',",
" tools=['//test:compiler'],",
")",
"sh_binary(",
" name='compiler',",
" srcs=['compiler.sh'],",
" licenses=['restricted'],",
" output_licenses=['notice'],",
")");
ConfiguredTarget target = getConfiguredTarget("//test:gen");
Map<Label, License> actual = Maps.filterKeys(getTransitiveLicenses(target),
CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses("//test:compiler", "notice");
assertSameMapEntries(expected, actual);
}
@Test
public void testNonHostAttributeCannotBeTool() throws Exception {
scratch.file("keyboardmonkeys/BUILD",
"genrule(name='million_monkeys',",
" licenses=['restricted'],",
" output_licenses=['notice'],",
" outs=['source.sh'],",
" cmd='type furiously on typewriters')");
scratch.file("product/BUILD",
"sh_binary(name='product',",
" srcs=['//keyboardmonkeys:source.sh'])");
ConfiguredTarget product = getConfiguredTarget("//product:product");
Map<Label, License> actual = Maps.filterKeys(
getTransitiveLicenses(product), CC_OR_JAVA_OR_SH_LABEL_FILTER);
Map<Label, License> expected = licenses("//keyboardmonkeys:million_monkeys", "restricted");
assertSameMapEntries(expected, actual);
}
@Test
public void testCcToolchainLicenseOverride() throws Exception {
scratch.file("c/BUILD",
"filegroup(name = 'dynamic-runtime-libs-cherry', srcs = [], licenses = ['restricted'])",
"cc_toolchain(",
" name = 'c',",
" output_licenses = ['notice'],",
" cpu = 'cherry',",
" ar_files = 'ar-cherry',",
" as_files = 'as-cherry',",
" compiler_files = 'compile-cherry',",
" dwp_files = 'dwp-cherry',",
" coverage_files = 'gcov-cherry',",
" linker_files = 'link-cherry',",
" strip_files = ':every-file',",
" objcopy_files = 'objcopy-cherry',",
" all_files = ':every-file',",
" dynamic_runtime_libs = ['dynamic-runtime-libs-cherry'],",
" static_runtime_libs = ['static-runtime-libs-cherry'])");
ConfiguredTarget target = getConfiguredTarget("//c:c");
Map<Label, License> expected = licenses("//c:c", "notice");
Map<Label, License> actual = getTransitiveLicenses(target);
assertSameMapEntries(expected, actual);
}
@Test
public void testLicenseParsing() throws Exception {
License l1 = License.parseLicense(Arrays.asList("restricted",
"exception=//a:a"));
License l2 = License.parseLicense(Arrays.asList("restricted",
"reciprocal", "exception=//a:a"));
License l3 = License.parseLicense(Arrays.asList("by_exception_only",
"reciprocal", "exception=//a:a", "exception=//b:b"));
assertThat(l1.toString()).isEqualTo("[restricted] with exceptions [//a:a]");
assertThat(l2.toString()).isEqualTo("[restricted, reciprocal] with exceptions [//a:a]");
assertThat(l3.toString())
.isEqualTo("[by_exception_only, reciprocal] with exceptions [//a:a, //b:b]");
}
/**
* Takes a list of strings, which alternate labels with license lists, and
* returns a map of labels to licenses. The license strings are comma-separated
* strings.
*/
protected static Map<Label, License> licenses(String... strings)
throws LicenseParsingException, LabelSyntaxException {
Map<Label, License> result = new HashMap<>();
for (int i = 0; i < strings.length; i += 2) {
String labelStr = strings[i];
String licStr = strings[i + 1];
Label label = Label.parseAbsolute(labelStr);
List<String> splitLicenses =
licStr.isEmpty() ? Arrays.<String>asList() : Arrays.asList(licStr.split(","));
License license = License.parseLicense(splitLicenses);
result.put(label, license);
}
return result;
}
protected static<K, V> void assertSameMapEntries(Map<K, V> expected, Map<K, V> actual) {
if (expected.size() != actual.size()) {
StringBuilder actualString = new StringBuilder();
for (K key : actual.keySet()) {
actualString.append(key + ": " + actual.get(key) + "\n");
}
int expectedSize = expected.size();
assertWithMessage("Expected map of size '%s' but found map of size '%s', actual value:\n%s",
expectedSize, actual.size(), actualString)
.that(actual)
.hasSize(expectedSize);
}
for (K key : expected.keySet()) {
V expectedValue = expected.get(key);
V actualValue = actual.get(key);
assertWithMessage("Key '%s'", key).that(actualValue).isNotNull();
assertWithMessage("Values for key '" + key + "' should match")
.that(actualValue)
.isEqualTo(expectedValue);
}
}
@Test
public void testDualLicensedUsesLeastRestrictive() throws Exception {
scratch.file("user/BUILD",
"sh_binary(name = 'user',",
" srcs = ['user.sh'],",
" deps = ['//used'])");
scratch.file("used/BUILD",
"licenses(['restricted', 'permissive'])",
"sh_library(name = 'used',",
" srcs=['used.sh'])");
ConfiguredTarget used = getConfiguredTarget("//used");
Map<Label, License> usedActual =
Maps.filterKeys(getTransitiveLicenses(used), AnalysisMock.get().ccSupport().labelFilter());
Label usedLabel = Label.parseAbsolute("//used");
License license = usedActual.get(usedLabel);
license.checkCompatibility(EnumSet.of(DistributionType.CLIENT),
getTarget("//user"), usedLabel, reporter, false);
assertNoEvents();
}
/** Regression test for b/9811855. */
@Test
public void testFilegroupLicenses() throws Exception {
scratch.file("user/BUILD",
"sh_binary(name = 'user',",
" srcs = ['user.sh'],",
" deps = ['//used'])");
scratch.file("used/BUILD",
"licenses(['restricted'])",
"filegroup(name = 'used',",
" licenses=['unencumbered'],",
" srcs=['used.sh'])"); // used.sh is not 'restricted'
ConfiguredTarget used = getConfiguredTarget("//used");
Map<Label, License> usedActual =
Maps.filterKeys(getTransitiveLicenses(used), AnalysisMock.get().ccSupport().labelFilter());
Label usedLabel = Label.parseAbsolute("//used");
License license = usedActual.get(usedLabel);
license.checkCompatibility(EnumSet.of(DistributionType.CLIENT),
getTarget("//user"), usedLabel, reporter, false);
assertNoEvents();
}
/**
* Regression test for b/4159051: "Latest blaze release broke --check_licenses"
*/
@Test
public void testLicenseCheckingTakesOnlyOneSelectBranch() throws Exception {
scratch.file("eden/BUILD",
"config_setting(",
" name = 'config_a',",
" values = {'define': 'mode=a'})",
"cc_library(name = 'eve',",
" deps = select({",
" ':config_a': ['//third_party/fruit:peach'],",
" '//conditions:default': ['//third_party/fruit:apple'],",
" }),",
" distribs = ['client'])");
scratch.file("third_party/fruit/BUILD",
"cc_library(name='apple', licenses=['restricted'])",
"cc_library(name='peach', licenses=['unencumbered'])");
useConfiguration("--check_licenses", "--define", "mode=a");
ConfiguredTarget eve = getConfiguredTarget("//eden:eve");
Map<Label, License> eveActual =
Maps.filterKeys(getTransitiveLicenses(eve), AnalysisMock.get().ccSupport().labelFilter());
Map<Label, License> eveExpected = licenses("//third_party/fruit:peach", "unencumbered");
assertSameMapEntries(eveExpected, eveActual);
assertNoEvents();
}
@Test
public void configSettingsHaveNoLicense() throws Exception {
scratch.file("third_party/restricted/BUILD",
"licenses(['by_exception_only'])",
"config_setting(",
" name = 'a_setting',",
" values = {'define': 'mode=a'})");
useConfiguration("--check_licenses", "--define", "mode=a");
ConfiguredTarget configSetting = getConfiguredTarget("//third_party/restricted:a_setting");
assertThat(configSetting.getProvider(LicensesProvider.class).getTransitiveLicenses())
.isEmpty();
}
@Test
public void testJavaToolchainOutputLicense() throws Exception {
scratch.file("java/a/BUILD",
"java_toolchain(",
" name = 'toolchain',",
" licenses = ['restricted'],",
" output_licenses = ['unencumbered'],",
" encoding = 'UTF-8',",
" source_version = '8',",
" target_version = '8',",
" bootclasspath = [':bcp'],",
" extclasspath = [':ecp'],",
" javac = [':langtools'],",
" javabuilder = ['javabuilder'],",
" header_compiler = ['header_compiler'],",
" singlejar = ['singlejar'],",
" genclass = ['genclass'],",
" ijar = ['ijar'])",
"java_binary(",
" name = 'a',",
" srcs = ['a.java'])");
useConfiguration("--java_toolchain=//java/a:toolchain", "--check_licenses");
ConfiguredTarget bin = getConfiguredTarget("//java/a:a");
Map<Label, License> licenses = getTransitiveLicenses(bin);
License toolchainLicense = licenses.get(Label.parseAbsoluteUnchecked("//java/a:toolchain"));
assertThat(toolchainLicense).isNotEqualTo(License.parseLicense(ImmutableList.of("restricted")));
assertThat(toolchainLicense).isEqualTo(License.parseLicense(ImmutableList.of("unencumbered")));
}
@Test
public void testTargetLicenseEquality() throws Exception {
Label label1 = Label.parseAbsolute("//foo");
Label label2 = Label.parseAbsolute("//bar");
License restricted = License.parseLicense(ImmutableList.of("restricted"));
License unencumbered = License.parseLicense(ImmutableList.of("unencumbered"));
new EqualsTester()
.addEqualityGroup(
new TargetLicense(label1, restricted),
new TargetLicense(label1, restricted))
.addEqualityGroup(
new TargetLicense(label2, restricted),
new TargetLicense(label2, restricted))
.addEqualityGroup(
new TargetLicense(label2, unencumbered),
new TargetLicense(label2, unencumbered))
.testEquals();
}
/**
* Gets the licenses of all targets that are in the transitive closure of a
* target. The result includes this target itself.
*
* @return a map from target labels to licenses
*/
protected static Map<Label, License> getTransitiveLicenses(ConfiguredTarget target) {
final ImmutableMap.Builder<Label, License> result = ImmutableMap.builder();
LicensesProvider provider = target.getProvider(LicensesProvider.class);
if (provider != null) {
for (TargetLicense targetLicense : provider.getTransitiveLicenses()) {
result.put(targetLicense.getLabel(), targetLicense.getLicense());
}
}
return result.build();
}
}