Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for ResolvedToolchainContext with missing optional toolchains. #15296

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement;
import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
Expand Down Expand Up @@ -48,25 +49,26 @@ public static ResolvedToolchainContext load(
Iterable<ConfiguredTargetAndData> toolchainTargets)
throws ToolchainException {

ImmutableMap.Builder<ToolchainTypeInfo, ToolchainInfo> toolchains =
ImmutableMap.Builder<ToolchainTypeInfo, ToolchainInfo> toolchainsBuilder =
new ImmutableMap.Builder<>();
ImmutableList.Builder<TemplateVariableInfo> templateVariableProviders =
new ImmutableList.Builder<>();

for (ConfiguredTargetAndData target : toolchainTargets) {
// Aliases are in toolchainTypeToResolved by the original alias label, not via the final
// target's label.
Label discoveredLabel = target.getConfiguredTarget().getOriginalLabel();
ToolchainInfo toolchainInfo = PlatformProviderUtils.toolchain(target.getConfiguredTarget());

for (ToolchainTypeInfo toolchainType :
unloadedToolchainContext.toolchainTypeToResolved().inverse().get(discoveredLabel)) {
ToolchainInfo toolchainInfo = PlatformProviderUtils.toolchain(target.getConfiguredTarget());

// If the toolchainType hadn't been resolved to an actual target, resolution would have
// failed with an error much earlier. However, the target might still not be an actual
// toolchain.
if (toolchainType != null) {
if (toolchainInfo != null) {
toolchains.put(toolchainType, toolchainInfo);
toolchainsBuilder.put(toolchainType, toolchainInfo);
} else {
throw new TargetNotToolchainException(toolchainType, discoveredLabel);
}
Expand All @@ -81,6 +83,20 @@ public static ResolvedToolchainContext load(
}
}

// Verify that all mandatory toolchain type requirements are present.
ImmutableMap<ToolchainTypeInfo, ToolchainInfo> toolchains = toolchainsBuilder.buildOrThrow();
for (ToolchainTypeRequirement toolchainTypeRequirement :
unloadedToolchainContext.toolchainTypes()) {
if (toolchainTypeRequirement.mandatory()) {
Label toolchainTypeLabel = toolchainTypeRequirement.toolchainType();
ToolchainTypeInfo toolchainTypeInfo =
unloadedToolchainContext.requestedLabelToToolchainType().get(toolchainTypeLabel);
if (!toolchains.containsKey(toolchainTypeInfo)) {
throw new MissingToolchainTypeRequirementException(toolchainTypeRequirement);
}
}
}

return new AutoValue_ResolvedToolchainContext(
// super:
unloadedToolchainContext.key(),
Expand All @@ -91,7 +107,7 @@ public static ResolvedToolchainContext load(
// this:
targetDescription,
unloadedToolchainContext.requestedLabelToToolchainType(),
toolchains.buildOrThrow(),
toolchains,
templateVariableProviders.build());
}

Expand Down Expand Up @@ -125,7 +141,7 @@ public ToolchainInfo forToolchainType(ToolchainTypeInfo toolchainType) {
}

/**
* Exception used when a toolchain type is required but the resolved target does not have
* Exception used when a toolchain type is requested but the resolved target does not have
* ToolchainInfo.
*/
static final class TargetNotToolchainException extends ToolchainException {
Expand All @@ -143,4 +159,20 @@ protected Code getDetailedCode() {
return Code.MISSING_PROVIDER;
}
}

/** Exception used when a toolchain type is required but noimplementation was found. */
private static class MissingToolchainTypeRequirementException extends ToolchainException {

MissingToolchainTypeRequirementException(ToolchainTypeRequirement toolchainTypeRequirement) {
super(
String.format(
"toolchain type %s was mandatory but is not present",
toolchainTypeRequirement.toolchainType()));
}

@Override
protected Code getDetailedCode() {
return Code.NO_MATCHING_TOOLCHAIN;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.devtools.build.lib.skyframe.ToolchainException;
import com.google.devtools.build.lib.skyframe.UnloadedToolchainContext;
import com.google.devtools.build.lib.skyframe.UnloadedToolchainContextImpl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand All @@ -38,7 +39,17 @@
@RunWith(JUnit4.class)
public class ResolvedToolchainContextTest extends ToolchainTestCase {

// TODO(https://github.com/bazelbuild/bazel/issues/14726): Add tests for optional toolchain types.
Label optionalToolchainTypeLabel;
ToolchainTypeRequirement optionalToolchainType;
ToolchainTypeInfo optionalToolchainTypeInfo;

@Before
public void createOptionalToolchainType() {
optionalToolchainTypeLabel = Label.parseAbsoluteUnchecked("//toolchain:optional_toolchain");
optionalToolchainType =
ToolchainTypeRequirement.builder(optionalToolchainTypeLabel).mandatory(false).build();
optionalToolchainTypeInfo = ToolchainTypeInfo.create(optionalToolchainTypeLabel);
}

@Test
public void load() throws Exception {
Expand Down Expand Up @@ -90,6 +101,165 @@ public void load() throws Exception {
.isEqualTo("baz");
}

@Test
public void load_mandatory_missing() throws Exception {
ToolchainContextKey toolchainContextKey =
ToolchainContextKey.key()
.configurationKey(targetConfigKey)
.toolchainTypes(testToolchainType)
.build();

// Create a static UnloadedToolchainContext.
UnloadedToolchainContext unloadedToolchainContext =
UnloadedToolchainContextImpl.builder(toolchainContextKey)
.setExecutionPlatform(linuxPlatform)
.setTargetPlatform(linuxPlatform)
.setToolchainTypes(ImmutableSet.of(testToolchainType))
.setRequestedLabelToToolchainType(
ImmutableMap.of(testToolchainTypeLabel, testToolchainTypeInfo))
.build();

// Resolve toolchains.
assertThrows(
ToolchainException.class,
() -> ResolvedToolchainContext.load(unloadedToolchainContext, "test", ImmutableList.of()));
}

@Test
public void load_optional_present() throws Exception {
addToolchain(
"extra",
"extra_toolchain_linux",
ImmutableList.of("//constraints:linux"),
ImmutableList.of("//constraints:linux"),
"baz");

ToolchainContextKey toolchainContextKey =
ToolchainContextKey.key()
.configurationKey(targetConfigKey)
.toolchainTypes(optionalToolchainType)
.build();

// Create a static UnloadedToolchainContext.
UnloadedToolchainContext unloadedToolchainContext =
UnloadedToolchainContextImpl.builder(toolchainContextKey)
.setExecutionPlatform(linuxPlatform)
.setTargetPlatform(linuxPlatform)
.setToolchainTypes(ImmutableSet.of(optionalToolchainType))
.setRequestedLabelToToolchainType(
ImmutableMap.of(optionalToolchainTypeLabel, optionalToolchainTypeInfo))
.setToolchainTypeToResolved(
ImmutableSetMultimap.<ToolchainTypeInfo, Label>builder()
.put(
optionalToolchainTypeInfo,
Label.parseAbsoluteUnchecked("//extra:extra_toolchain_linux_impl"))
.build())
.build();

// Create the prerequisites.
ConfiguredTargetAndData toolchain =
getConfiguredTargetAndData(
Label.parseAbsoluteUnchecked("//extra:extra_toolchain_linux_impl"), targetConfig);

// Resolve toolchains.
ResolvedToolchainContext toolchainContext =
ResolvedToolchainContext.load(
unloadedToolchainContext, "test", ImmutableList.of(toolchain));
assertThat(toolchainContext).isNotNull();
assertThat(toolchainContext).hasToolchainType(optionalToolchainTypeLabel);
assertThat(toolchainContext)
.forToolchainType(optionalToolchainTypeLabel)
.getValue("data")
.isEqualTo("baz");
}

@Test
public void load_optional_missing() throws Exception {
ToolchainContextKey toolchainContextKey =
ToolchainContextKey.key()
.configurationKey(targetConfigKey)
.toolchainTypes(optionalToolchainType)
.build();

// Create a static UnloadedToolchainContext.
UnloadedToolchainContext unloadedToolchainContext =
UnloadedToolchainContextImpl.builder(toolchainContextKey)
.setExecutionPlatform(linuxPlatform)
.setTargetPlatform(linuxPlatform)
.setToolchainTypes(ImmutableSet.of(optionalToolchainType))
.setRequestedLabelToToolchainType(
ImmutableMap.of(optionalToolchainTypeLabel, optionalToolchainTypeInfo))
.build();

// Resolve toolchains.
ResolvedToolchainContext toolchainContext =
ResolvedToolchainContext.load(unloadedToolchainContext, "test", ImmutableList.of());
assertThat(toolchainContext).isNotNull();

// Missing optional toolchain type requirement is present.
assertThat(toolchainContext).hasToolchainType(optionalToolchainTypeLabel);
// Missing optional toolchain implementation is null.
assertThat(toolchainContext).forToolchainType(optionalToolchainTypeLabel).isNull();
}

@Test
public void load_mixed() throws Exception {
addToolchain(
"extra",
"extra_toolchain_linux",
ImmutableList.of("//constraints:linux"),
ImmutableList.of("//constraints:linux"),
"baz");

ToolchainContextKey toolchainContextKey =
ToolchainContextKey.key()
.configurationKey(targetConfigKey)
.toolchainTypes(testToolchainType, optionalToolchainType)
.build();

// Create a static UnloadedToolchainContext.
UnloadedToolchainContext unloadedToolchainContext =
UnloadedToolchainContextImpl.builder(toolchainContextKey)
.setExecutionPlatform(linuxPlatform)
.setTargetPlatform(linuxPlatform)
.setToolchainTypes(ImmutableSet.of(testToolchainType, optionalToolchainType))
.setRequestedLabelToToolchainType(
ImmutableMap.<Label, ToolchainTypeInfo>builder()
.put(testToolchainTypeLabel, testToolchainTypeInfo)
.put(optionalToolchainTypeLabel, optionalToolchainTypeInfo)
.build())
.setToolchainTypeToResolved(
ImmutableSetMultimap.<ToolchainTypeInfo, Label>builder()
.put(
testToolchainTypeInfo,
Label.parseAbsoluteUnchecked("//extra:extra_toolchain_linux_impl"))
.build())
.build();

// Create the prerequisites.
ConfiguredTargetAndData testToolchain =
getConfiguredTargetAndData(
Label.parseAbsoluteUnchecked("//extra:extra_toolchain_linux_impl"), targetConfig);

// Resolve toolchains.
ResolvedToolchainContext toolchainContext =
ResolvedToolchainContext.load(
unloadedToolchainContext, "test", ImmutableList.of(testToolchain));
assertThat(toolchainContext).isNotNull();

// Test toolchain is present.
assertThat(toolchainContext).hasToolchainType(testToolchainTypeLabel);
assertThat(toolchainContext)
.forToolchainType(testToolchainTypeLabel)
.getValue("data")
.isEqualTo("baz");

// Missing optional toolchain type requirement is present.
assertThat(toolchainContext).hasToolchainType(optionalToolchainTypeLabel);
// Missing optional toolchain implementation is null.
assertThat(toolchainContext).forToolchainType(optionalToolchainTypeLabel).isNull();
}

@Test
public void load_aliasedToolchain() throws Exception {
scratch.file(
Expand Down