blob: ab9c57ae0faefd2997029217cdaca90713240320 [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.skylark;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.EventBus;
import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.skyframe.AspectValue;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import javax.annotation.Nullable;
/**
* Tests for Skylark aspects
*/
@RunWith(JUnit4.class)
public class SkylarkAspectsTest extends BuildViewTestCase {
@Test
public void testAspect() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _impl(target, ctx):",
" print('This aspect does nothing')",
" return struct()",
"MyAspect = aspect(implementation=_impl)");
scratch.file("test/BUILD", "java_library(name = 'xxx',)");
AnalysisResult analysisResult =
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
assertThat(
transform(
analysisResult.getTargetsToBuild(),
new Function<ConfiguredTarget, String>() {
@Nullable
@Override
public String apply(ConfiguredTarget configuredTarget) {
return configuredTarget.getLabel().toString();
}
}))
.containsExactly("//test:xxx");
assertThat(
transform(
analysisResult.getAspects(),
new Function<AspectValue, String>() {
@Nullable
@Override
public String apply(AspectValue aspectValue) {
return String.format(
"%s(%s)",
aspectValue.getConfiguredAspect().getName(),
aspectValue.getLabel().toString());
}
}))
.containsExactly("//test:aspect.bzl%MyAspect(//test:xxx)");
}
@Test
public void testAspectPropagating() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _impl(target, ctx):",
" s = set([target.label])",
" for i in ctx.rule.attr.deps:",
" s += i.target_labels",
" return struct(target_labels = s)",
"",
"MyAspect = aspect(",
" implementation=_impl,",
" attr_aspects=['deps'],",
")");
scratch.file(
"test/BUILD",
"java_library(",
" name = 'yyy',",
")",
"java_library(",
" name = 'xxx',",
" srcs = ['A.java'],",
" deps = [':yyy'],",
")");
AnalysisResult analysisResult =
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
assertThat(
transform(
analysisResult.getTargetsToBuild(),
new Function<ConfiguredTarget, String>() {
@Nullable
@Override
public String apply(ConfiguredTarget configuredTarget) {
return configuredTarget.getLabel().toString();
}
}))
.containsExactly("//test:xxx");
AspectValue aspectValue = analysisResult.getAspects().iterator().next();
SkylarkProviders skylarkProviders =
aspectValue.getConfiguredAspect().getProvider(SkylarkProviders.class);
assertThat(skylarkProviders).isNotNull();
Object names = skylarkProviders.getValue("target_labels");
assertThat(names).isInstanceOf(SkylarkNestedSet.class);
assertThat(
transform(
(SkylarkNestedSet) names,
new Function<Object, String>() {
@Nullable
@Override
public String apply(Object o) {
assertThat(o).isInstanceOf(Label.class);
return o.toString();
}
}))
.containsExactly("//test:xxx", "//test:yyy");
}
@Test
public void testAspectsFromSkylarkRules() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _aspect_impl(target, ctx):",
" s = set([target.label])",
" for i in ctx.rule.attr.deps:",
" s += i.target_labels",
" return struct(target_labels = s)",
"",
"def _rule_impl(ctx):",
" s = set([])",
" for i in ctx.attr.attr:",
" s += i.target_labels",
" return struct(rule_deps = s)",
"",
"MyAspect = aspect(",
" implementation=_aspect_impl,",
" attr_aspects=['deps'],",
")",
"my_rule = rule(",
" implementation=_rule_impl,",
" attrs = { 'attr' : ",
" attr.label_list(mandatory=True, allow_files=True, aspects = [MyAspect]) },",
")");
scratch.file(
"test/BUILD",
"load('/test/aspect', 'my_rule')",
"java_library(",
" name = 'yyy',",
")",
"my_rule(",
" name = 'xxx',",
" attr = [':yyy'],",
")");
AnalysisResult analysisResult =
update(
ImmutableList.of("//test:xxx"),
ImmutableList.<String>of(),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
assertThat(
transform(
analysisResult.getTargetsToBuild(),
new Function<ConfiguredTarget, String>() {
@Nullable
@Override
public String apply(ConfiguredTarget configuredTarget) {
return configuredTarget.getLabel().toString();
}
}))
.containsExactly("//test:xxx");
ConfiguredTarget target = analysisResult.getTargetsToBuild().iterator().next();
SkylarkProviders skylarkProviders = target.getProvider(SkylarkProviders.class);
assertThat(skylarkProviders).isNotNull();
Object names = skylarkProviders.getValue("rule_deps");
assertThat(names).isInstanceOf(SkylarkNestedSet.class);
assertThat(
transform(
(SkylarkNestedSet) names,
new Function<Object, String>() {
@Nullable
@Override
public String apply(Object o) {
assertThat(o).isInstanceOf(Label.class);
return o.toString();
}
}))
.containsExactly("//test:yyy");
}
@Test
public void testAspectFailingExecution() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _impl(target, ctx):",
" return 1/0",
"",
"MyAspect = aspect(implementation=_impl)");
scratch.file("test/BUILD", "java_library(name = 'xxx',)");
reporter.removeHandler(failFastHandler);
try {
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
} catch (ViewCreationFailedException e) {
// expect to fail.
}
assertContainsEvent(
"ERROR /workspace/test/BUILD:1:1: in java_library rule //test:xxx: \n"
+ "Traceback (most recent call last):\n"
+ "\tFile \"/workspace/test/BUILD\", line 1\n"
+ "\t\t//test:aspect.bzl%MyAspect(...)\n"
+ "\tFile \"/workspace/test/aspect.bzl\", line 2, in _impl\n"
+ "\t\t1 / 0\n"
+ "integer division by zero");
}
@Test
public void testAspectFailingReturnsNotAStruct() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _impl(target, ctx):",
" return 0",
"",
"MyAspect = aspect(implementation=_impl)");
scratch.file("test/BUILD", "java_library(name = 'xxx',)");
reporter.removeHandler(failFastHandler);
try {
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
} catch (ViewCreationFailedException e) {
// expect to fail.
}
assertContainsEvent("Aspect implementation doesn't return a struct");
}
@Test
public void testAspectFailingReturnsUnsafeObject() throws Exception {
scratch.file(
"test/aspect.bzl",
"def foo():",
" return 0",
"def _impl(target, ctx):",
" return struct(x = foo)",
"",
"MyAspect = aspect(implementation=_impl)");
scratch.file("test/BUILD", "java_library(name = 'xxx',)");
reporter.removeHandler(failFastHandler);
try {
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
} catch (ViewCreationFailedException e) {
// expect to fail.
}
assertContainsEvent(
"ERROR /workspace/test/BUILD:1:1: in java_library rule //test:xxx: \n"
+ "\n"
+ "\n"
+ "/workspace/test/aspect.bzl:4:11: Value of provider 'x' is of an illegal type: function");
}
@Test
public void testAspectFailingOrphanArtifacts() throws Exception {
scratch.file(
"test/aspect.bzl",
"def _impl(target, ctx):",
" ctx.new_file('missing_in_action.txt')",
" return struct()",
"",
"MyAspect = aspect(implementation=_impl)");
scratch.file("test/BUILD", "java_library(name = 'xxx',)");
reporter.removeHandler(failFastHandler);
try {
update(
ImmutableList.of("//test:xxx"),
ImmutableList.of("test/aspect.bzl%MyAspect"),
false,
LOADING_PHASE_THREADS,
true,
new EventBus());
} catch (ViewCreationFailedException e) {
// expect to fail.
}
assertContainsEvent(
"ERROR /workspace/test/BUILD:1:1: in java_library rule //test:xxx: \n"
+ "\n"
+ "\n"
+ "The following files have no generating action:\n"
+ "test/missing_in_action.txt\n");
}
}