blob: d2a76c9341200ec0b87e3baed9f8d26514a57702 [file] [log] [blame]
// 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.rules.platform;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.platform.ConstraintSettingInfo;
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests Skylark API for {@link PlatformInfo} providers. */
@RunWith(JUnit4.class)
public class PlatformInfoApiTest extends BuildViewTestCase {
@Test
public void testPlatform() throws Exception {
constraintBuilder("//foo:basic").addConstraintValue("value1").write();
platformBuilder("//foo:my_platform").addConstraint("value1").write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
ConstraintSettingInfo constraintSetting =
ConstraintSettingInfo.create(makeLabel("//foo:basic"));
ConstraintValueInfo constraintValue =
ConstraintValueInfo.create(constraintSetting, makeLabel("//foo:value1"));
assertThat(platformInfo.constraints().get(constraintSetting)).isEqualTo(constraintValue);
assertThat(platformInfo.remoteExecutionProperties()).isEmpty();
}
@Test
public void testPlatform_overlappingConstraintValueError() throws Exception {
List<String> lines =
new ImmutableList.Builder<String>()
.addAll(
constraintBuilder("//foo:basic")
.addConstraintValue("value1")
.addConstraintValue("value2")
.lines())
.addAll(
platformBuilder("//foo:my_platform")
.addConstraint("value1")
.addConstraint("value2")
.lines())
.build();
checkError(
"foo",
"my_platform",
"Duplicate constraint_values detected: "
+ "constraint_setting //foo:basic has [//foo:value1, //foo:value2]",
lines.toArray(new String[] {}));
}
@Test
public void testPlatform_remoteExecution() throws Exception {
platformBuilder("//foo:my_platform").setRemoteExecutionProperties("foo: val1").write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
assertThat(platformInfo.remoteExecutionProperties()).isEqualTo("foo: val1");
}
@Test
public void testPlatform_parent() throws Exception {
constraintBuilder("//foo:setting1").addConstraintValue("value1").write();
constraintBuilder("//foo:setting2").addConstraintValue("value2").write();
platformBuilder("//foo:parent_platform").addConstraint("value1").write();
platformBuilder("//foo:my_platform")
.setParent("//foo:parent_platform")
.addConstraint("value2")
.write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
ConstraintSettingInfo constraintSetting1 =
ConstraintSettingInfo.create(makeLabel("//foo:setting1"));
ConstraintValueInfo constraintValue1 =
ConstraintValueInfo.create(constraintSetting1, makeLabel("//foo:value1"));
assertThat(platformInfo.constraints().get(constraintSetting1)).isEqualTo(constraintValue1);
ConstraintSettingInfo constraintSetting2 =
ConstraintSettingInfo.create(makeLabel("//foo:setting2"));
ConstraintValueInfo constraintValue2 =
ConstraintValueInfo.create(constraintSetting2, makeLabel("//foo:value2"));
assertThat(platformInfo.constraints().get(constraintSetting2)).isEqualTo(constraintValue2);
}
@Test
public void testPlatform_parent_override() throws Exception {
constraintBuilder("//foo:setting1")
.addConstraintValue("value1a")
.addConstraintValue("value1b")
.write();
platformBuilder("//foo:parent_platform").addConstraint("value1a").write();
platformBuilder("//foo:my_platform").addConstraint("value1b").write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
ConstraintSettingInfo constraintSetting1 =
ConstraintSettingInfo.create(makeLabel("//foo:setting1"));
ConstraintValueInfo constraintValue1 =
ConstraintValueInfo.create(constraintSetting1, makeLabel("//foo:value1b"));
assertThat(platformInfo.constraints().get(constraintSetting1)).isEqualTo(constraintValue1);
}
@Test
public void testPlatform_parent_remoteExecProperties_entireOverride() throws Exception {
platformBuilder("//foo:parent_platform").setRemoteExecutionProperties("parent props").write();
platformBuilder("//foo:my_platform")
.setParent("//foo:parent_platform")
.setRemoteExecutionProperties("child props")
.write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
assertThat(platformInfo.remoteExecutionProperties()).isEqualTo("child props");
}
@Test
public void testPlatform_parent_remoteExecProperties_includeParent() throws Exception {
platformBuilder("//foo:parent_platform").setRemoteExecutionProperties("parent props").write();
platformBuilder("//foo:my_platform")
.setParent("//foo:parent_platform")
.setRemoteExecutionProperties("child ({PARENT_REMOTE_EXECUTION_PROPERTIES}) props")
.write();
assertNoEvents();
PlatformInfo platformInfo = fetchPlatformInfo("//foo:my_platform");
assertThat(platformInfo).isNotNull();
assertThat(platformInfo.remoteExecutionProperties()).isEqualTo("child (parent props) props");
}
@Test
public void testPlatform_parent_tooManyParentsError() throws Exception {
List<String> lines =
new ImmutableList.Builder<String>()
.addAll(platformBuilder("//foo:parent_platform1").lines())
.addAll(platformBuilder("//foo:parent_platform2").lines())
.addAll(
ImmutableList.of(
"platform(name = 'my_platform',\n",
" parents = [\n",
" ':parent_platform1',\n",
" ':parent_platform2',\n",
" ])"))
.build();
checkError(
"foo",
"my_platform",
"in parents attribute of platform rule //foo:my_platform: "
+ "parents attribute must have a single value",
lines.toArray(new String[] {}));
}
ConstraintBuilder constraintBuilder(String name) {
return new ConstraintBuilder(name);
}
final class ConstraintBuilder {
private final Label label;
private final List<String> constraintValues = new ArrayList<>();
private String defaultConstraintValue = null;
public ConstraintBuilder(String name) {
this.label = Label.parseAbsoluteUnchecked(name);
}
public ConstraintBuilder defaultConstraintValue(String defaultConstraintValue) {
this.defaultConstraintValue = defaultConstraintValue;
this.constraintValues.add(defaultConstraintValue);
return this;
}
public ConstraintBuilder addConstraintValue(String constraintValue) {
this.constraintValues.add(constraintValue);
return this;
}
public List<String> lines() {
ImmutableList.Builder<String> lines = ImmutableList.builder();
// Add the constraint setting.
lines.add("constraint_setting(name = '" + label.getName() + "',");
if (!Strings.isNullOrEmpty(defaultConstraintValue)) {
lines.add(" default_constraint_value = ':" + defaultConstraintValue + "',");
}
lines.add(")");
// Add the constraint values.
for (String constraintValue : constraintValues) {
lines.add(
"constraint_value(",
" name = '" + constraintValue + "',",
" constraint_setting = ':" + label.getName() + "',",
")");
}
return lines.build();
}
public void write() throws Exception {
List<String> lines = lines();
String filename = label.getPackageFragment().getRelative("BUILD").getPathString();
scratch.appendFile(filename, lines.toArray(new String[] {}));
}
}
PlatformBuilder platformBuilder(String name) {
return new PlatformBuilder(name);
}
final class PlatformBuilder {
private final Label label;
private final List<String> constraintValues = new ArrayList<>();
private Label parentLabel = null;
private String remoteExecutionProperties = "";
public PlatformBuilder(String name) {
this.label = Label.parseAbsoluteUnchecked(name);
}
public PlatformBuilder setParent(String parentLabel) {
this.parentLabel = Label.parseAbsoluteUnchecked(parentLabel);
return this;
}
public PlatformBuilder addConstraint(String value) {
this.constraintValues.add(value);
return this;
}
public PlatformBuilder setRemoteExecutionProperties(String value) {
this.remoteExecutionProperties = value;
return this;
}
public List<String> lines() {
ImmutableList.Builder<String> lines = ImmutableList.builder();
lines.add("platform(", " name = '" + label.getName() + "',");
if (parentLabel != null) {
lines.add(" parents = ['" + parentLabel + "'],");
}
lines.add(" constraint_values = [");
for (String name : constraintValues) {
lines.add(" ':" + name + "',");
}
lines.add(" ],");
if (!Strings.isNullOrEmpty(remoteExecutionProperties)) {
lines.add(" remote_execution_properties = '" + remoteExecutionProperties + "',");
}
lines.add(")");
return lines.build();
}
public void write() throws Exception {
List<String> lines = lines();
String filename = label.getPackageFragment().getRelative("BUILD").getPathString();
scratch.appendFile(filename, lines.toArray(new String[] {}));
}
}
@Nullable
ConstraintSettingInfo fetchConstraintSettingInfo(String label) throws Exception {
ConfiguredTarget target = getConfiguredTarget(label);
return PlatformProviderUtils.constraintSetting(target);
}
@Nullable
PlatformInfo fetchPlatformInfo(String platformLabel) throws Exception {
ConfiguredTarget target = getConfiguredTarget(platformLabel);
return PlatformProviderUtils.platform(target);
}
}