| // Copyright 2018 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.truth.Truth.assertThat; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.common.collect.Iterables; | |
| import com.google.devtools.build.lib.actions.AbstractAction; | |
| import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; | |
| import com.google.devtools.build.lib.actions.Artifact; | |
| import com.google.devtools.build.lib.analysis.AnalysisResult; | |
| import com.google.devtools.build.lib.analysis.ConfiguredAspect; | |
| import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.packages.SkylarkProvider.SkylarkKey; | |
| import com.google.devtools.build.lib.packages.StructImpl; | |
| import com.google.devtools.build.lib.syntax.Dict; | |
| import com.google.devtools.build.lib.syntax.Mutability; | |
| import com.google.devtools.build.lib.syntax.Sequence; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| /** Tests for the Starlark-accessible actions provider on rule configured targets. */ | |
| @RunWith(JUnit4.class) | |
| public class SkylarkActionProviderTest extends AnalysisTestCase { | |
| @Test | |
| public void aspectGetsActionProviderForNativeRule() throws Exception { | |
| scratch.file( | |
| "test/aspect.bzl", | |
| "foo = provider()", | |
| "def _impl(target, ctx):", | |
| " return [foo(actions = target.actions)]", | |
| "MyAspect = aspect(implementation=_impl)"); | |
| scratch.file( | |
| "test/BUILD", | |
| "genrule(", | |
| " name = 'xxx',", | |
| " cmd = 'echo \"hello\" > $@',", | |
| " outs = ['mygen.out']", | |
| ")"); | |
| AnalysisResult analysisResult = | |
| update(ImmutableList.of("test/aspect.bzl%MyAspect"), "//test:xxx"); | |
| ConfiguredAspect configuredAspect = | |
| Iterables.getOnlyElement(analysisResult.getAspects()).getConfiguredAspect(); | |
| SkylarkKey fooKey = | |
| new SkylarkKey(Label.parseAbsolute("//test:aspect.bzl", ImmutableMap.of()), "foo"); | |
| StructImpl fooProvider = (StructImpl) configuredAspect.get(fooKey); | |
| assertThat(fooProvider.getValue("actions")).isNotNull(); | |
| @SuppressWarnings("unchecked") | |
| Sequence<ActionAnalysisMetadata> actions = | |
| (Sequence<ActionAnalysisMetadata>) fooProvider.getValue("actions"); | |
| assertThat(actions).isNotEmpty(); | |
| ActionAnalysisMetadata action = actions.get(0); | |
| assertThat(action.getMnemonic()).isEqualTo("Genrule"); | |
| assertThat(action).isInstanceOf(AbstractAction.class); | |
| assertThat(((AbstractAction) action).getExecutionInfo()).isNotNull(); | |
| } | |
| @Test | |
| @SuppressWarnings("unchecked") | |
| public void aspectGetsActionProviderForSkylarkRule() throws Exception { | |
| scratch.file( | |
| "test/aspect.bzl", | |
| "foo = provider()", | |
| "def _impl(target, ctx):", | |
| " mnemonics = [a.mnemonic for a in target.actions]", | |
| " envs = [a.env for a in target.actions]", | |
| " execution_info = [a.execution_info for a in target.actions]", | |
| " inputs = [a.inputs.to_list() for a in target.actions]", | |
| " outputs = [a.outputs.to_list() for a in target.actions]", | |
| " argv = [a.argv for a in target.actions]", | |
| " return [foo(", | |
| " actions = target.actions,", | |
| " mnemonics = mnemonics,", | |
| " envs = envs,", | |
| " execution_info = execution_info,", | |
| " inputs = inputs,", | |
| " outputs = outputs,", | |
| " argv = argv", | |
| " )]", | |
| "MyAspect = aspect(implementation=_impl)"); | |
| scratch.file( | |
| "test/rule.bzl", | |
| "def impl(ctx):", | |
| " output_file0 = ctx.actions.declare_file('myfile0')", | |
| " output_file1 = ctx.actions.declare_file('myfile1')", | |
| " executable = ctx.actions.declare_file('executable')", | |
| " ctx.actions.run(outputs=[output_file0], executable=executable,", | |
| " mnemonic='MyAction0', env={'foo':'bar', 'pet':'puppy'})", | |
| " ctx.actions.run_shell(outputs=[executable, output_file1],", | |
| " command='fakecmd', mnemonic='MyAction1', env={'pet':'bunny'})", | |
| " return None", | |
| "my_rule = rule(impl)"); | |
| scratch.file( | |
| "test/BUILD", "load('//test:rule.bzl', 'my_rule')", "my_rule(", " name = 'xxx',", ")"); | |
| useConfiguration("--experimental_google_legacy_api"); | |
| AnalysisResult analysisResult = | |
| update(ImmutableList.of("test/aspect.bzl%MyAspect"), "//test:xxx"); | |
| ConfiguredAspect configuredAspect = | |
| Iterables.getOnlyElement(analysisResult.getAspects()).getConfiguredAspect(); | |
| SkylarkKey fooKey = | |
| new SkylarkKey(Label.parseAbsolute("//test:aspect.bzl", ImmutableMap.of()), "foo"); | |
| StructImpl fooProvider = (StructImpl) configuredAspect.get(fooKey); | |
| assertThat(fooProvider.getValue("actions")).isNotNull(); | |
| Sequence<ActionAnalysisMetadata> actions = | |
| (Sequence<ActionAnalysisMetadata>) fooProvider.getValue("actions"); | |
| assertThat(actions).hasSize(2); | |
| Sequence<String> mnemonics = (Sequence<String>) fooProvider.getValue("mnemonics"); | |
| assertThat(mnemonics).containsExactly("MyAction0", "MyAction1"); | |
| Sequence<Dict<String, String>> envs = | |
| (Sequence<Dict<String, String>>) fooProvider.getValue("envs"); | |
| assertThat(envs) | |
| .containsExactly( | |
| Dict.of((Mutability) null, "foo", "bar", "pet", "puppy"), | |
| Dict.of((Mutability) null, "pet", "bunny")); | |
| Sequence<Dict<String, String>> executionInfo = | |
| (Sequence<Dict<String, String>>) fooProvider.getValue("execution_info"); | |
| assertThat(executionInfo).isNotNull(); | |
| Sequence<Sequence<Artifact>> inputs = | |
| (Sequence<Sequence<Artifact>>) fooProvider.getValue("inputs"); | |
| assertThat(flattenArtifactNames(inputs)).containsExactly("executable"); | |
| Sequence<Sequence<Artifact>> outputs = | |
| (Sequence<Sequence<Artifact>>) fooProvider.getValue("outputs"); | |
| assertThat(flattenArtifactNames(outputs)).containsExactly("myfile0", "executable", "myfile1"); | |
| Sequence<Sequence<String>> argv = (Sequence<Sequence<String>>) fooProvider.getValue("argv"); | |
| assertThat(argv.get(0)).hasSize(1); | |
| assertThat(argv.get(0).get(0)).endsWith("executable"); | |
| assertThat(argv.get(1)).contains("fakecmd"); | |
| } | |
| private static List<String> flattenArtifactNames(Sequence<Sequence<Artifact>> artifactLists) { | |
| return artifactLists.stream() | |
| .flatMap(artifacts -> artifacts.stream()) | |
| .map(artifact -> artifact.getFilename()) | |
| .collect(Collectors.toList()); | |
| } | |
| } |