| // 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.starlark; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.collect.ImmutableList; |
| 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.StarlarkProvider; |
| import com.google.devtools.build.lib.packages.StructImpl; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| import net.starlark.java.eval.Dict; |
| import net.starlark.java.eval.Sequence; |
| 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 StarlarkActionProviderTest 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.getAspectsMap().values()); |
| |
| StarlarkProvider.Key fooKey = |
| new StarlarkProvider.Key(Label.parseCanonical("//test:aspect.bzl"), "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); |
| } |
| |
| @Test |
| @SuppressWarnings("unchecked") |
| public void aspectGetsActionProviderForStarlarkRule() 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.getAspectsMap().values()); |
| |
| StarlarkProvider.Key fooKey = |
| new StarlarkProvider.Key(Label.parseCanonical("//test:aspect.bzl"), "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.builder().put("foo", "bar").put("pet", "puppy").buildImmutable(), |
| Dict.builder().put("pet", "bunny").buildImmutable()); |
| |
| 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()); |
| } |
| } |