// Copyright 2016 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.skyframe;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.common.base.VerifyException;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.Dependency;
import com.google.devtools.build.lib.analysis.DependencyResolver;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
import com.google.devtools.build.lib.testutil.Suite;
import com.google.devtools.build.lib.testutil.TestSpec;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
import com.google.devtools.build.skyframe.EvaluationResult;
import com.google.devtools.build.skyframe.LegacySkyKey;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests {@link ConfiguredTargetFunction}'s logic for determining each target's
* {@link BuildConfiguration}.
*
*
This is essentially an integration test for
* {@link ConfiguredTargetFunction#computeDependencies} and {@link DependencyResolver}. These
* methods form the core logic that figures out what a target's deps are, how their configurations
* should differ from their parent, and how to instantiate those configurations as tangible
* {@link BuildConfiguration} objects.
*
*
{@link ConfiguredTargetFunction} is a complicated class that does a lot of things. This test
* focuses purely on the task of determining configurations for deps. So instead of evaluating
* full {@link ConfiguredTargetFunction} instances, it evaluates a mock {@link SkyFunction} that
* just wraps the {@link ConfiguredTargetFunction#computeDependencies} part. This keeps focus tight
* and integration dependencies narrow.
*
*
We can't just call {@link ConfiguredTargetFunction#computeDependencies} directly because that
* method needs a {@link SkyFunction.Environment} and Blaze's test infrastructure doesn't support
* direct access to environments.
*/
@TestSpec(size = Suite.SMALL_TESTS)
@RunWith(JUnit4.class)
public class ConfigurationsForTargetsTest extends AnalysisTestCase {
/**
* A mock {@link SkyFunction} that just calls {@link ConfiguredTargetFunction#computeDependencies}
* and returns its results.
*/
private static class ComputeDependenciesFunction implements SkyFunction {
static final SkyFunctionName SKYFUNCTION_NAME =
SkyFunctionName.create("CONFIGURED_TARGET_FUNCTION_COMPUTE_DEPENDENCIES");
private final LateBoundStateProvider stateProvider;
ComputeDependenciesFunction(LateBoundStateProvider lateBoundStateProvider) {
this.stateProvider = lateBoundStateProvider;
}
/**
* Returns a {@link SkyKey} for a given pair.
*/
static SkyKey key(Target target, BuildConfiguration config) {
return LegacySkyKey.create(SKYFUNCTION_NAME, new TargetAndConfiguration(target, config));
}
/**
* Returns a {@link OrderedSetMultimap} map representing the
* deps of given target.
*/
static class Value implements SkyValue {
OrderedSetMultimap depMap;
Value(OrderedSetMultimap depMap) {
this.depMap = depMap;
}
}
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
throws EvalException, InterruptedException {
try {
OrderedSetMultimap depMap =
ConfiguredTargetFunction.computeDependencies(
env,
new SkyframeDependencyResolver(env),
(TargetAndConfiguration) skyKey.argument(),
ImmutableList.of(),
ImmutableMap.