// 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.skyframe;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;

import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.skyframe.TransitiveBaseTraversalFunction.TargetAndErrorIfAnyImpl;
import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
import com.google.devtools.build.lib.util.GroupedList;
import com.google.devtools.build.lib.util.GroupedList.GroupedListHelper;
import com.google.devtools.build.skyframe.EvaluationResult;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyframeLookupResult;
import com.google.devtools.build.skyframe.ValueOrUntypedException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;

/** Test for {@link TransitiveTraversalFunction}. */
@RunWith(JUnit4.class)
public class TransitiveTraversalFunctionTest extends BuildViewTestCase {

  @Test
  public void noRepeatedLabelVisitationForTransitiveTraversalFunction() throws Exception {
    // Create a basic package with a target //foo:foo.
    Label label = Label.parseCanonical("//foo:foo");
    scratch.file("foo/BUILD", "sh_library(name = '" + label.getName() + "')");
    Package pkg = loadPackage(label.getPackageIdentifier());
    TargetAndErrorIfAnyImpl targetAndErrorIfAny =
        new TargetAndErrorIfAnyImpl(
            /*packageLoadedSuccessfully=*/ true,
            /*errorLoadingTarget=*/ null,
            pkg.getTarget(label.getName()));
    TransitiveTraversalFunction function =
        new TransitiveTraversalFunction() {
          @Override
          TargetAndErrorIfAny loadTarget(Environment env, Label label) {
            return targetAndErrorIfAny;
          }
        };
    // Create the GroupedList saying we had already requested two targets the last time we called
    // #compute.
    GroupedListHelper<SkyKey> helper = new GroupedListHelper<>();
    SkyKey fakeDep1 = function.getKey(Label.parseCanonical("//foo:bar"));
    SkyKey fakeDep2 = function.getKey(Label.parseCanonical("//foo:baz"));
    helper.add(PackageValue.key(label.getPackageIdentifier()));
    helper.startGroup();
    // Note that these targets don't actually exist in the package we created initially. It doesn't
    // matter for the purpose of this test, the original package was just to create some objects
    // that we needed.
    helper.add(fakeDep1);
    helper.add(fakeDep2);
    helper.endGroup();
    GroupedList<SkyKey> groupedList = new GroupedList<>();
    groupedList.append(helper);
    AtomicBoolean wasOptimizationUsed = new AtomicBoolean(false);
    SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
    when(mockEnv.getTemporaryDirectDeps()).thenReturn(groupedList);
    when(mockEnv.getValuesAndExceptions(groupedList.get(1)))
        .thenAnswer(
            (invocationOnMock) -> {
              wasOptimizationUsed.set(true);
              // It doesn't matter what this SkyframeLookupResult is, we'll return true in the
              // valuesMissing() call.
              return new SkyframeLookupResult(
                  /* valuesMissingCallback= */ () -> {},
                  k -> {
                    throw new IllegalStateException("Shouldn't have been called: " + k);
                  });
            });
    when(mockEnv.valuesMissing()).thenReturn(true);

    // Run the compute function and check that we returned null.
    assertThat(function.compute(function.getKey(label), mockEnv)).isNull();

    // Verify that the mock was called with the arguments we expected.
    assertThat(wasOptimizationUsed.get()).isTrue();
  }

  @Test
  public void multipleErrorsForTransitiveTraversalFunction() throws Exception {
    Label label = Label.parseCanonical("//foo:foo");
    scratch.file(
        "foo/BUILD", "sh_library(name = '" + label.getName() + "', deps = [':bar', ':baz'])");
    Package pkg = loadPackage(label.getPackageIdentifier());
    TargetAndErrorIfAnyImpl targetAndErrorIfAny =
        new TargetAndErrorIfAnyImpl(
            /*packageLoadedSuccessfully=*/ true,
            /*errorLoadingTarget=*/ null,
            pkg.getTarget(label.getName()));
    TransitiveTraversalFunction function =
        new TransitiveTraversalFunction() {
          @Override
          TargetAndErrorIfAny loadTarget(Environment env, Label label) {
            return targetAndErrorIfAny;
          }
        };
    SkyKey dep1 = function.getKey(Label.parseCanonical("//foo:bar"));
    SkyKey dep2 = function.getKey(Label.parseCanonical("//foo:baz"));
    SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
    NoSuchTargetException exp1 = new NoSuchTargetException("bad bar");
    NoSuchTargetException exp2 = new NoSuchTargetException("bad baz");
    SkyframeLookupResult returnedDeps =
        new SkyframeLookupResult(
            () -> {},
            key ->
                key.equals(dep1)
                    ? ValueOrUntypedException.ofExn(exp1)
                    : key.equals(dep2) ? ValueOrUntypedException.ofExn(exp2) : null);

    when(mockEnv.getValuesAndExceptions(ImmutableSet.of(dep1, dep2))).thenReturn(returnedDeps);
    when(mockEnv.valuesMissing()).thenReturn(false);

    assertThat(
            ((TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv))
                .getErrorMessage())
        .isEqualTo("bad bar");
  }

  @Test
  public void selfErrorWins() throws Exception {
    Label label = Label.parseCanonical("//foo:foo");
    scratch.file("foo/BUILD", "sh_library(name = '" + label.getName() + "', deps = [':bar'])");
    Package pkg = loadPackage(label.getPackageIdentifier());
    TargetAndErrorIfAnyImpl targetAndErrorIfAny =
        new TargetAndErrorIfAnyImpl(
            /*packageLoadedSuccessfully=*/ true,
            /*errorLoadingTarget=*/ new NoSuchTargetException("self error is long and last"),
            pkg.getTarget(label.getName()));
    TransitiveTraversalFunction function =
        new TransitiveTraversalFunction() {
          @Override
          TargetAndErrorIfAny loadTarget(Environment env, Label label) {
            return targetAndErrorIfAny;
          }
        };
    SkyKey dep = function.getKey(Label.parseCanonical("//foo:bar"));
    NoSuchTargetException exp = new NoSuchTargetException("bad bar");
    SkyframeLookupResult returnedDep =
        new SkyframeLookupResult(
            () -> {}, key -> key.equals(dep) ? ValueOrUntypedException.ofExn(exp) : null);
    SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
    when(mockEnv.getValuesAndExceptions(ImmutableSet.of(dep))).thenReturn(returnedDep);
    when(mockEnv.valuesMissing()).thenReturn(false);

    TransitiveTraversalValue transitiveTraversalValue =
        (TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv);
    assertThat(transitiveTraversalValue.getErrorMessage()).isEqualTo("self error is long and last");
  }

  @Test
  public void getStrictLabelAspectKeys() throws Exception {
    Label label = Label.parseCanonical("//test:foo");
    scratch.file(
        "test/aspect.bzl",
        "def _aspect_impl(target, ctx):",
        "   return struct()",
        "def _rule_impl(ctx):",
        "   return struct()",
        "",
        "MyAspect = aspect(",
        "   implementation=_aspect_impl,",
        "   attr_aspects=['deps'],",
        "   attrs = { '_extra_deps' : attr.label(default = Label('//foo:bar'))},",
        ")",
        "my_rule = rule(",
        "   implementation=_rule_impl,",
        "   attrs = { 'attr' : ",
        "             attr.label_list(mandatory=True, aspects = [MyAspect]) ",
        "           },",
        ")");
    scratch.file(
        "test/BUILD",
        "load('//test:aspect.bzl', 'my_rule')",
        "my_rule(name = 'foo',attr = [':bad'])");
    Package pkg = loadPackage(label.getPackageIdentifier());
    TargetAndErrorIfAnyImpl targetAndErrorIfAny =
        new TargetAndErrorIfAnyImpl(
            /*packageLoadedSuccessfully=*/ true,
            /*errorLoadingTarget=*/ null,
            pkg.getTarget(label.getName()));
    TransitiveTraversalFunction function =
        new TransitiveTraversalFunction() {
          @Override
          TargetAndErrorIfAny loadTarget(Environment env, Label label) {
            return targetAndErrorIfAny;
          }
        };
    SkyKey badDep = function.getKey(Label.parseCanonical("//test:bad"));
    NoSuchTargetException exp = new NoSuchTargetException("bad test");
    AtomicBoolean valuesMissing = new AtomicBoolean(false);
    SkyframeLookupResult returnedDep =
        new SkyframeLookupResult(
            () -> valuesMissing.set(true),
            key -> key.equals(badDep) ? ValueOrUntypedException.ofExn(exp) : null);
    SkyFunction.Environment mockEnv = Mockito.mock(SkyFunction.Environment.class);
    when(mockEnv.getValuesAndExceptions(ImmutableSet.of(badDep))).thenReturn(returnedDep);

    TransitiveTraversalValue transitiveTraversalValue =
        (TransitiveTraversalValue) function.compute(function.getKey(label), mockEnv);
    assertThat(transitiveTraversalValue.getErrorMessage()).isEqualTo("bad test");
    assertThat(valuesMissing.get()).isFalse();
  }

  /* Invokes the loading phase, using Skyframe. */
  private Package loadPackage(PackageIdentifier pkgid)
      throws InterruptedException, NoSuchPackageException {
    SkyKey key = PackageValue.key(pkgid);
    EvaluationResult<PackageValue> result =
        SkyframeExecutorTestUtils.evaluate(
            getSkyframeExecutor(), key, /*keepGoing=*/ false, reporter);
    if (result.hasError()) {
      throw (NoSuchPackageException) result.getError(key).getException();
    }
    return result.get(key).getPackage();
  }
}
