// Copyright 2020 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.runtime.commands;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.buildtool.util.BuildIntegrationTestCase;
import com.google.devtools.build.lib.runtime.BlazeCommandDispatcher;
import com.google.devtools.build.lib.runtime.commands.ConfigCommand.ConfigurationDiffForOutput;
import com.google.devtools.build.lib.runtime.commands.ConfigCommand.ConfigurationForOutput;
import com.google.devtools.build.lib.runtime.commands.ConfigCommand.FragmentDiffForOutput;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.io.RecordingOutErr;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Tests for {@link ConfigCommand} ("<code>$ blaze config</code>").
 *
 * <p>These tests assume all important testable properties are determined in {@link ConfigCommand},
 * so the output formatter used doesn't affect those properties. We test with <code>--output=json
 * </code> for easy parsing.
 */
@RunWith(JUnit4.class)
public class ConfigCommandTest extends BuildIntegrationTestCase {
  private BlazeCommandDispatcher dispatcher;

  @Before
  public final void init() throws Exception {
    getRuntime().overrideCommands(ImmutableList.of(new BuildCommand(), new ConfigCommand()));
    dispatcher = new BlazeCommandDispatcher(getRuntime());
    write(
        "tools/allowlists/function_transition_allowlist/BUILD",
        "package_group(",
        "    name = 'function_transition_allowlist',",
        "    packages = ['//...'],",
        ")");
    write(
        "test/defs.bzl",
        "def _simple_rule_impl(ctx):",
        "  pass",
        "simple_rule = rule(",
        "  implementation = _simple_rule_impl,",
        "  attrs = {},",
        ")",
        "def _sometransition_impl(settings, attr):",
        "  _ignore = (settings, attr)",
        "  return {'//command_line_option:platform_suffix': 'transitioned'}",
        "_sometransition = transition(",
        "  implementation = _sometransition_impl,",
        "  inputs = [],",
        "  outputs = ['//command_line_option:platform_suffix'],",
        ")",
        "rule_with_transition = rule(",
        "  implementation = _simple_rule_impl,",
        "  cfg = _sometransition,",
        "  attrs = {",
        "    '_allowlist_function_transition': attr.label(",
        "        default = '//tools/allowlists/function_transition_allowlist'),",
        "  },",
        ")");
    write(
        "test/BUILD",
        "load('//test:defs.bzl', 'simple_rule', 'rule_with_transition')",
        "simple_rule(name='buildme')",
        "rule_with_transition(name='buildme_with_transition')");
  }

  /**
   * Performs loading and analysis on the fixed rule <code>//test:buildme</code> with the given
   * build options (as they'd appear on the command line).
   */
  private void analyzeTarget(String... args) throws Exception {
    List<String> params = Lists.newArrayList("build");
    // Basic flags required to make any build work. Ideally we'd go through BlazeRuntimeWrapper,
    // which does the same setup. But that's explicitly documented as not supported command
    // invocations, which is exactly what we we need here.
    params.addAll(TestConstants.PRODUCT_SPECIFIC_FLAGS);
    params.add("//test:buildme");
    params.add("--nobuild"); // Execution phase isn't necessary to collect configurations.
    Collections.addAll(params, args);
    dispatcher.exec(params, "my client", outErr);
  }

  /**
   * Performs loading and analysis on the fixed rule <code>//test:buildme</code> with the given
   * build options (as they'd appear on the command line).
   */
  private void analyzeTargetWithTransition(String... args) throws Exception {
    List<String> params = Lists.newArrayList("build");
    // Basic flags required to make any build work. Ideally we'd go through BlazeRuntimeWrapper,
    // which does the same setup. But that's explicitly documented as not supported command
    // invocations, which is exactly what we we need here.
    params.addAll(TestConstants.PRODUCT_SPECIFIC_FLAGS);
    params.add("//test:buildme_with_transition");
    params.add("--nobuild"); // Execution phase isn't necessary to collect configurations.
    Collections.addAll(params, args);
    dispatcher.exec(params, "my client", outErr);
  }

  /**
   * Calls <cod>blaze config --output=json</code> with the given flags and returns the raw output.
   *
   * <p>Should be called after {@link #analyzeTarget} so there are actual configs to read.
   */
  private RecordingOutErr callConfigCommand(String... args) throws Exception {
    List<String> params = Lists.newArrayList("config");
    params.add("--output=json");
    Collections.addAll(params, args);
    RecordingOutErr recordingOutErr = new RecordingOutErr();
    dispatcher.exec(params, "my client", recordingOutErr);
    return recordingOutErr;
  }

  /**
   * Returns the value of an option under a configuration's {@link FragmentOptions}.
   *
   * <p>Throws {@link NoSuchElementException} if it can't be found.
   */
  private static String getOptionValue(
      ConfigurationForOutput config, String fragmentOptions, String optionName) {
    List<String> ans =
        config.fragmentOptions.stream()
            .filter(fragment -> fragment.name.endsWith(fragmentOptions))
            .flatMap(fragment -> fragment.options.entrySet().stream())
            .filter(setting -> setting.getKey().equals(optionName))
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());
    if (ans.size() > 1) {
      throw new NoSuchElementException(
          String.format(
              "Multiple matches for fragment=%s, option=%s", fragmentOptions, optionName));
    } else if (ans.isEmpty()) {
      throw new NoSuchElementException(
          String.format("No matches for fragment=%s, option=%s", fragmentOptions, optionName));
    }
    return ans.get(0);
  }

  private static boolean isTargetConfig(ConfigurationForOutput config) {
    if (config.mnemonic.endsWith("-noconfig")) {
      return false;
    }
    return !Boolean.parseBoolean(getOptionValue(config, "CoreOptions", "is exec configuration"));
  }

  /** Converts {@code a.b.d} to {@code d}. */
  private static String getBaseName(String str) {
    return str.substring(str.lastIndexOf(".") + 1);
  }

  /** Converts a list of {@code a.b.d} strings to {@code d} form. */
  private static List<String> getBaseNames(List<String> list) {
    return list.stream().map(ConfigCommandTest::getBaseName).collect(Collectors.toList());
  }

  @Test
  public void showConfigIds() throws Exception {
    analyzeTarget();
    JsonObject fullJson =
        JsonParser.parseString(callConfigCommand().outAsLatin1()).getAsJsonObject();
    // Should be: target configuration, target configuration without test.
    assertThat(fullJson).isNotNull();
    assertThat(fullJson.has("configuration-IDs")).isTrue();
    assertThat(fullJson.get("configuration-IDs").getAsJsonArray().size()).isEqualTo(3);
  }

  private boolean skipNoConfig(JsonElement configHash) {
    try {
      return !new Gson()
          .fromJson(
              callConfigCommand(configHash.getAsString()).outAsLatin1(),
              ConfigurationForOutput.class)
          .mnemonic
          .contains("-noconfig");
    } catch (Exception e) {
      assertWithMessage("Failed to retrieve %s: %s", configHash.getAsString(), e.getMessage())
          .fail();
      return false;
    }
  }

  /**
   * Calls the config command to return all config hashes currently available.
   *
   * @param includeNoConfig if true, include the "noconfig" configuration (see {@link
   *     com.google.devtools.build.lib.analysis.config.transitions.NoConfigTransition}. Else filter
   *     it out.
   */
  private ImmutableList<String> getConfigHashes(boolean includeNoConfig) throws Exception {
    return JsonParser.parseString(callConfigCommand().outAsLatin1())
        .getAsJsonObject()
        .get("configuration-IDs")
        .getAsJsonArray()
        .asList()
        .stream()
        .filter(includeNoConfig ? Predicates.alwaysTrue() : this::skipNoConfig)
        .map(c -> c.getAsString())
        .collect(toImmutableList());
  }

  @Test
  public void showSingleConfig() throws Exception {
    analyzeTarget();
    // Find the first non-noconfig configuration (see NoConfigTransition). noconfig is a special
    // configuration that strips away most of its structure, so not a good candidate for this test.
    String configHash = getConfigHashes(/* includeNoConfig= */ false).get(0);
    ConfigurationForOutput config =
        new Gson()
            .fromJson(callConfigCommand(configHash).outAsLatin1(), ConfigurationForOutput.class);

    assertThat(config).isNotNull();
    // Verify config metadata:
    assertThat(config.configHash).isEqualTo(configHash);
    assertThat(config.skyKey).isEqualTo(String.format("BuildConfigurationKey[%s]", configHash));
    // Verify the existence of a couple of expected fragments:
    assertThat(
            config.fragments.stream()
                .map(
                    fragment ->
                        Pair.of(getBaseName(fragment.name), getBaseNames(fragment.fragmentOptions)))
                .collect(Collectors.toList()))
        .containsAtLeast(
            Pair.of("PlatformConfiguration", ImmutableList.of("PlatformOptions")),
            Pair.of("TestConfiguration", ImmutableList.of("TestConfiguration$TestOptions")));
    // Verify the existence of a couple of expected fragment options:
    assertThat(
            config.fragmentOptions.stream()
                .map(fragment -> getBaseName(fragment.name))
                .collect(Collectors.toList()))
        .containsAtLeast("PlatformOptions", "CoreOptions", "user-defined");
    // Verify the existence of a couple of expected option names:
    assertThat(
            config.fragmentOptions.stream()
                .filter(fragment -> fragment.name.endsWith("CoreOptions"))
                .flatMap(fragment -> fragment.options.keySet().stream())
                .collect(Collectors.toList()))
        .containsAtLeast("run_under", "check_visibility", "stamp");
  }

  @Test
  public void showSingleConfigHashPrefix() throws Exception {
    analyzeTarget();
    String configHash =
        JsonParser.parseString(callConfigCommand().outAsLatin1())
            .getAsJsonObject()
            .get("configuration-IDs")
            .getAsJsonArray()
            .get(0)
            .getAsString();
    String hashPrefix = configHash.substring(0, configHash.length() / 2);
    ConfigurationForOutput config =
        new Gson()
            .fromJson(callConfigCommand(hashPrefix).outAsLatin1(), ConfigurationForOutput.class);
    assertThat(config).isNotNull();
    assertThat(config.configHash).startsWith(hashPrefix);
  }

  @Test
  public void unknownHashPrefix() throws Exception {
    analyzeTarget();
    String configHash =
        JsonParser.parseString(callConfigCommand().outAsLatin1())
            .getAsJsonObject()
            .get("configuration-IDs")
            .getAsJsonArray()
            .get(0)
            .getAsString();
    // No valid hash has spaces.
    String hashPrefix = configHash.substring(0, configHash.length() / 2) + " ";
    assertThat(callConfigCommand(hashPrefix).errAsLatin1())
        .contains("No configuration found with ID prefix " + hashPrefix);
  }

  @Test
  public void showAllConfigs() throws Exception {
    analyzeTarget();

    int numConfigs = 0;
    for (JsonElement configJson :
        JsonParser.parseString(callConfigCommand("--dump_all").outAsLatin1()).getAsJsonArray()) {
      ConfigurationForOutput config = new Gson().fromJson(configJson, ConfigurationForOutput.class);
      assertThat(config).isNotNull();
      numConfigs++;
    }
    assertThat(numConfigs).isEqualTo(3); // Target + target w/o test + nonConfig.
  }

  @Test
  public void compareConfigs() throws Exception {
    // Do not trim test configuration for now to make 'finding' the configurations easier.
    analyzeTargetWithTransition("--platform_suffix=pure", "--notrim_test_configuration");
    String targetConfig1Hash = getTargetConfig().configHash;
    String targetConfig2Hash =
        getTargetConfig(/*excludedHashes=*/ ImmutableSet.of(targetConfig1Hash)).configHash;

    // Get their diff.
    String result = callConfigCommand(targetConfig1Hash, targetConfig2Hash).outAsLatin1();
    ConfigurationDiffForOutput diff = new Gson().fromJson(result, ConfigurationDiffForOutput.class);
    assertThat(diff).isNotNull();
    assertThat(diff.configHash1).isEqualTo(targetConfig1Hash);
    assertThat(diff.configHash2).isEqualTo(targetConfig2Hash);
    FragmentDiffForOutput fragmentDiff = Iterables.getOnlyElement(diff.fragmentsDiff);
    assertThat(fragmentDiff.name).endsWith("CoreOptions");
    Map.Entry<String, Pair<String, String>> optionDiff =
        Iterators.getOnlyElement(
            fragmentDiff.optionsDiff.entrySet().stream()
                .filter(x -> !x.getKey().equals("affected by starlark transition"))
                .iterator());
    assertThat(optionDiff.getKey()).isEqualTo("platform_suffix");
    // Convert from Pair<firstVal, secondVal> to an ImmutableList because the ordering of the
    // difference depends on which configuration comes first, which depends on the configuration
    // hash name, which we can't predict statically.
    assertThat(ImmutableList.of(optionDiff.getValue().first, optionDiff.getValue().second))
        .containsExactly("pure", "transitioned");
  }

  @Test
  public void compareConfigsHashPrefix() throws Exception {
    // Do not trim test configuration for now to make 'finding' the configurations easier.
    analyzeTargetWithTransition("--platform_suffix=pure", "--notrim_test_configuration");
    String targetConfig1Hash = getTargetConfig().configHash;
    String targetConfig2Hash =
        getTargetConfig(/*excludedHashes=*/ ImmutableSet.of(targetConfig1Hash)).configHash;

    String hashPrefix1 = targetConfig1Hash.substring(0, targetConfig1Hash.length() / 2);
    String hashPrefix2 = targetConfig2Hash.substring(0, targetConfig2Hash.length() / 2);

    ConfigurationDiffForOutput diff =
        new Gson()
            .fromJson(
                callConfigCommand(hashPrefix1, hashPrefix2).outAsLatin1(),
                ConfigurationDiffForOutput.class);
    assertThat(diff).isNotNull();
    assertThat(diff.configHash1).startsWith(hashPrefix1);
    assertThat(diff.configHash2).startsWith(hashPrefix2);
  }

  private ConfigurationForOutput getTargetConfig() throws Exception {
    return getTargetConfig(ImmutableSet.of());
  }

  private ConfigurationForOutput getTargetConfig(ImmutableSet<String> excludedHashes)
      throws Exception {
    // Find a target configuration hash.
    for (JsonElement element :
        JsonParser.parseString(callConfigCommand().outAsLatin1())
            .getAsJsonObject()
            .get("configuration-IDs")
            .getAsJsonArray()) {
      String configHash = element.getAsString();
      if (excludedHashes.contains(configHash)) {
        continue;
      }
      ConfigurationForOutput config =
          new Gson()
              .fromJson(callConfigCommand(configHash).outAsLatin1(), ConfigurationForOutput.class);
      if (isTargetConfig(config)) {
        return config;
      }
    }
    throw new AssertionError("Should have found config hash");
  }

  @Test
  public void starlarkFlagsInUserDefinedFragment() throws Exception {
    write(
        "test/flagdef.bzl",
        "def _rule_impl(ctx):",
        "    return []",
        "string_flag = rule(",
        "    implementation = _rule_impl,",
        "    build_setting = config.string(flag = True)",
        ")",
        "simple_rule = rule(",
        "    implementation = _rule_impl,",
        "    attrs = {}",
        ")");
    write(
        "custom_flags/BUILD",
        "load('//test:flagdef.bzl', 'string_flag')",
        "string_flag(",
        "    name = 'my_flag',",
        "    build_setting_default = '')");

    analyzeTarget("--//custom_flags:my_flag=hello");

    ConfigurationForOutput targetConfig = null;
    String result = callConfigCommand("--dump_all").outAsLatin1();
    for (JsonElement configJson : JsonParser.parseString(result).getAsJsonArray()) {
      ConfigurationForOutput config = new Gson().fromJson(configJson, ConfigurationForOutput.class);
      if (isTargetConfig(config)) {
        targetConfig = config;
        break;
      }
    }

    assertThat(targetConfig).isNotNull();
    assertThat(getOptionValue(targetConfig, "user-defined", "//custom_flags:my_flag"))
        .isEqualTo("hello");
  }

  @Test
  public void defineFlagsIndividuallyListedInUserDefinedFragment() throws Exception {
    analyzeTarget("--define", "a=1", "--define", "b=2");

    ConfigurationForOutput targetConfig = null;
    for (JsonElement configJson :
        JsonParser.parseString(callConfigCommand("--dump_all").outAsLatin1()).getAsJsonArray()) {
      ConfigurationForOutput config = new Gson().fromJson(configJson, ConfigurationForOutput.class);
      if (isTargetConfig(config)) {
        targetConfig = config;
        break;
      }
    }

    assertThat(targetConfig).isNotNull();
    assertThat(getOptionValue(targetConfig, "user-defined", "--define:a")).isEqualTo("1");
    assertThat(getOptionValue(targetConfig, "user-defined", "--define:b")).isEqualTo("2");
    assertThat(
            targetConfig.fragmentOptions.stream()
                .filter(fragment -> fragment.name.endsWith("CoreOptions"))
                .flatMap(fragment -> fragment.options.keySet().stream())
                .filter(name -> name.equals("define"))
                .collect(Collectors.toList()))
        .isEmpty();
  }

  @Test
  public void conflictingDefinesLastWins() throws Exception {
    analyzeTarget("--define", "a=1", "--define", "a=2");

    ConfigurationForOutput targetConfig = null;
    for (JsonElement configJson :
        JsonParser.parseString(callConfigCommand("--dump_all").outAsLatin1()).getAsJsonArray()) {
      ConfigurationForOutput config = new Gson().fromJson(configJson, ConfigurationForOutput.class);
      if (isTargetConfig(config)) {
        targetConfig = config;
        break;
      }
    }

    assertThat(targetConfig).isNotNull();
    assertThat(getOptionValue(targetConfig, "user-defined", "--define:a")).isEqualTo("2");
    assertThat(
            targetConfig.fragmentOptions.stream()
                .filter(fragment -> fragment.name.endsWith("CoreOptions"))
                .flatMap(fragment -> fragment.options.keySet().stream())
                .filter(name -> name.equals("define"))
                .collect(Collectors.toList()))
        .isEmpty();
  }
}
