// Copyright 2019 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.blackbox.tests.manageddirs;

import static com.google.common.truth.Truth.assertThat;

import com.google.devtools.build.lib.blackbox.framework.BuilderRunner;
import com.google.devtools.build.lib.blackbox.framework.PathUtils;
import com.google.devtools.build.lib.blackbox.framework.ProcessResult;
import com.google.devtools.build.lib.blackbox.junit.AbstractBlackBoxTest;
import com.google.devtools.build.lib.util.ResourceFileLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;

/** Tests for managed directories. */
public class ManagedDirectoriesBlackBoxTest extends AbstractBlackBoxTest {
  private Random random;
  private Integer currentDebugId;

  @Override
  @Before
  public void setUp() throws Exception {
    random = new Random(17);
    super.setUp();
  }

  @Test
  public void testBuildProject() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();
  }

  @Test
  public void testNodeModulesDeleted() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();

    Path nodeModules = context().getWorkDir().resolve("node_modules");
    assertThat(nodeModules.toFile().isDirectory()).isTrue();
    PathUtils.deleteTree(nodeModules);

    buildExpectRepositoryRuleCalled();
    checkProjectFiles();
  }

  @Test
  public void testNodeModulesDeletedAndRecreated() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();

    Path nodeModules = context().getWorkDir().resolve("node_modules");
    assertThat(nodeModules.toFile().isDirectory()).isTrue();

    Path nodeModulesBackup = context().getWorkDir().resolve("node_modules_backup");
    PathUtils.copyTree(nodeModules, nodeModulesBackup);
    PathUtils.deleteTree(nodeModules);

    PathUtils.copyTree(nodeModulesBackup, nodeModules);

    buildExpectRepositoryRuleNotCalled();
    checkProjectFiles();
  }

  @Test
  public void testBuildProjectFetchNotRecalled() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();
    buildExpectRepositoryRuleNotCalled();
    checkProjectFiles();
  }

  private BuilderRunner bazel() {
    return bazel(false);
  }

  private BuilderRunner bazel(boolean watchFs) {
    currentDebugId = random.nextInt();
    BuilderRunner bazel = context().bazel().withEnv("DEBUG_ID", String.valueOf(currentDebugId));
    if (watchFs) {
      bazel.withFlags("--watchfs=true");
    }
    return bazel;
  }

  @Test
  public void testChangeOfFileTextUnderNodeModules() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();

    Path nodeModules = context().getWorkDir().resolve("node_modules");
    Path modulePackageJson = nodeModules.resolve("example-module/package.json");
    assertThat(modulePackageJson.toFile().exists()).isTrue();

    // Assert that non-structural changes are not detected.
    PathUtils.append(modulePackageJson, "# comment");

    buildExpectRepositoryRuleNotCalled();
    checkProjectFiles();
  }

  @Test
  public void testLoadIsNotCalledForManagedDirectories() throws Exception {
    generateProject();
    Path workspaceFile = context().getWorkDir().resolve(WORKSPACE);
    PathUtils.append(workspaceFile, "load('@non_existing//:target.bzl', 'some_symbol')");

    // Test that there is error when loading, so we parsed managed directories successfully.
    ProcessResult result = bazel().shouldFail().build("//...");
    assertThat(findPattern(result, "ERROR: Failed to load Starlark extension")).isTrue();
  }

  @Test
  public void testWithBazelTools() throws Exception {
    generateProject();
    Path workspaceFile = context().getWorkDir().resolve(WORKSPACE);
    PathUtils.append(
        workspaceFile,
        "load(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\", \"http_file\")");
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();
  }

  @Test
  public void testAddManagedDirectoriesLater() throws Exception {
    // Start the server, have things cached.
    context().write("BUILD", "");
    bazel().build("//...");

    // Now that we generate the project and have managed directories updated, we are also testing,
    // that managed directories are re-read correctly from the changed file.
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();

    // Test everything got cached.
    buildExpectRepositoryRuleNotCalled();
    checkProjectFiles();
  }

  @Test
  public void testFilesUnderChangedManagedDirectoriesRefreshed() throws Exception {
    doTestFilesUnderManagedDirectoriesRefreshed(false);
  }

  @Test
  public void testFilesUnderChangedManagedDirectoriesRefreshedWatchFs() throws Exception {
    doTestFilesUnderManagedDirectoriesRefreshed(true);
  }

  private void doTestFilesUnderManagedDirectoriesRefreshed(boolean watchFs) throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled(false, watchFs);
    checkProjectFiles();

    // Now remove the ManagedDirectories, and change the package version - it should still work.
    List<String> properWorkspaceText = context().read("WORKSPACE");

    context()
        .write(
            "WORKSPACE",
            "workspace(name = \"fine_grained_user_modules\")",
            "load(\":use_node_modules.bzl\", \"generate_fine_grained_node_modules\")",
            "generate_fine_grained_node_modules(name = \"generated_node_modules\",",
            "package_json = \"//:package.json\",)");
    Path packageJson =
        PathUtils.resolve(context().getWorkDir(), "node_modules", "example-module", "package.json");
    assertThat(packageJson.toFile().exists()).isTrue();

    // Now we are building it without managed directories, both managed directories and
    // RepositoryDirectoryValue will be dirty - we expect repository rule to be called again.
    buildExpectRepositoryRuleCalled(false, watchFs);
    checkProjectFiles();

    // Now change files directly in generated area, and build.
    List<String> oldPackageJson = PathUtils.readFile(packageJson);
    PathUtils.writeFile(
        packageJson,
        "{",
        "  \"license\": \"MIT\",",
        "  \"main\": \"example-module.js\",",
        "  \"name\": \"example-module\",",
        "  \"repository\": {",
        "    \"type\": \"git\",",
        "    \"url\": \"aaa\",",
        "  },",
        "  \"version\": \"7.7.7\"",
        "}");
    Path build = context().getWorkDir().resolve("BUILD");
    List<String> oldBuild = PathUtils.readFile(build);
    PathUtils.writeFile(
        build,
        "load(\":test_rule.bzl\", \"test_rule\")",
        "test_rule(",
        "    name = \"test_generated_deps\",",
        "    module_source = \"@generated_node_modules//:example-module\",",
        "    version = \"7.7.7\"",
        ")");

    // Test rule inputs has changed, so the build is not cached; however, the repository rule
    // is not rerun, since it's inputs (including managed directories settings) were not changed,
    // so debug_id is the same.
    buildExpectRepositoryRuleNotCalled();
    checkProjectFiles("7.7.7");

    // And is cached.
    buildExpectRepositoryRuleNotCalled();

    // Now change just the managed directories and see the generated version comes up.
    PathUtils.writeFile(
        context().getWorkDir().resolve(WORKSPACE), properWorkspaceText.toArray(new String[0]));
    PathUtils.writeFile(build, oldBuild.toArray(new String[0]));
    buildExpectRepositoryRuleCalled(false, watchFs);
    checkProjectFiles("0.2.0");
  }

  @Test
  public void testManagedDirectoriesSettingsAndManagedDirectoriesFilesChangeSimultaneously()
      throws Exception {
    doTestManagedDirectoriesSettingsAndManagedDirectoriesFilesChangeSimultaneously(false);
  }

  @Test
  public void testManagedDirectoriesSettingsAndManagedDirectoriesFilesChangeSimultaneouslyWatchFs()
      throws Exception {
    doTestManagedDirectoriesSettingsAndManagedDirectoriesFilesChangeSimultaneously(true);
  }

  private void doTestManagedDirectoriesSettingsAndManagedDirectoriesFilesChangeSimultaneously(
      boolean watchFs) throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled(false, watchFs);
    checkProjectFiles();

    // Modify managed directories somehow.
    context()
        .write(
            "WORKSPACE",
            "workspace(name = \"fine_grained_user_modules\",",
            "managed_directories = {'@generated_node_modules': ['node_modules', 'something']})",
            "load(\":use_node_modules.bzl\", \"generate_fine_grained_node_modules\")",
            "generate_fine_grained_node_modules(name = \"generated_node_modules\",",
            "package_json = \"//:package.json\",)");
    Path packageJson =
        PathUtils.resolve(context().getWorkDir(), "node_modules", "example-module", "package.json");
    assertThat(packageJson.toFile().exists()).isTrue();

    // Modify generated package.json under the managed directory.
    List<String> oldPackageJson = PathUtils.readFile(packageJson);
    PathUtils.writeFile(
        packageJson,
        "{",
        "  \"license\": \"MIT\",",
        "  \"main\": \"example-module.js\",",
        "  \"name\": \"example-module\",",
        "  \"repository\": {",
        "    \"type\": \"git\",",
        "    \"url\": \"aaa\",",
        "  },",
        "  \"version\": \"7.7.7\"",
        "}");
    // Expect files under managed directories be regenerated
    // and changes under managed directories be lost.
    buildExpectRepositoryRuleCalled(false, watchFs);
    checkProjectFiles();
  }

  @Test
  public void testRepositoryOverrideWithManagedDirectories() throws Exception {
    generateProject();

    Path override = context().getTmpDir().resolve("override");
    PathUtils.writeFile(override.resolve(WORKSPACE));
    // Just define some similar target.
    PathUtils.writeFile(
        override.resolve("BUILD"),
        "genrule(",
        "    name = \"example-module\",",
        "    srcs = [],",
        "    cmd = \"touch $(location package.json)\",",
        "    outs = [\"package.json\"],",
        "    visibility = ['//visibility:public'],",
        ")");

    BuilderRunner bazel =
        bazel().withFlags("--override_repository=generated_node_modules=" + override.toString());
    ProcessResult result = bazel.shouldFail().build("@generated_node_modules//:example-module");
    assertThat(result.errString())
        .contains(
            "ERROR: Overriding repositories is not allowed"
                + " for the repositories with managed directories."
                + "\nThe following overridden external repositories"
                + " have managed directories: @generated_node_modules");

    // Assert the result stays the same even when managed directories has not changed.
    result = bazel.shouldFail().build("@generated_node_modules//:example-module");
    assertThat(result.errString())
        .contains(
            "ERROR: Overriding repositories is not allowed"
                + " for the repositories with managed directories."
                + "\nThe following overridden external repositories"
                + " have managed directories: @generated_node_modules");
  }

  @Test
  public void testRepositoryOverrideChangeToConflictWithManagedDirectories() throws Exception {
    generateProject();
    buildExpectRepositoryRuleCalled();
    checkProjectFiles();

    Path override = context().getTmpDir().resolve("override");
    PathUtils.writeFile(override.resolve(WORKSPACE));
    // Just define some similar target.
    PathUtils.writeFile(
        override.resolve("BUILD"),
        "genrule(",
        "    name = \"example-module\",",
        "    srcs = [],",
        "    cmd = \"touch $(location package.json)\",",
        "    outs = [\"package.json\"],",
        "    visibility = ['//visibility:public'],",
        ")");

    // Now the overrides change.
    BuilderRunner bazel =
        bazel().withFlags("--override_repository=generated_node_modules=" + override.toString());
    ProcessResult result = bazel.shouldFail().build("@generated_node_modules//:example-module");
    assertThat(result.errString())
        .contains(
            "ERROR: Overriding repositories is not allowed"
                + " for the repositories with managed directories."
                + "\nThe following overridden external repositories"
                + " have managed directories: @generated_node_modules");
  }

  /**
   * The test to verify that WORKSPACE file can not be a symlink when managed directories are used.
   *
   * <p>The test of the case, when WORKSPACE file is a symlink, but not managed directories are
   * used, is in {@link WorkspaceBlackBoxTest#testWorkspaceFileIsSymlink()}
   */
  @Test
  public void testWorkspaceSymlinkThrowsWithManagedDirectories() throws Exception {
    generateProject();

    Path workspaceFile = context().getWorkDir().resolve(WORKSPACE);
    assertThat(workspaceFile.toFile().delete()).isTrue();

    Path tempWorkspace = Files.createTempFile(context().getTmpDir(), WORKSPACE, "");
    PathUtils.writeFile(
        tempWorkspace,
        "workspace(name = \"fine_grained_user_modules\",",
        "managed_directories = {'@generated_node_modules': ['node_modules']})",
        "",
        "load(\":use_node_modules.bzl\", \"generate_fine_grained_node_modules\")",
        "",
        "generate_fine_grained_node_modules(",
        "    name = \"generated_node_modules\",",
        "    package_json = \"//:package.json\",",
        ")");
    Files.createSymbolicLink(workspaceFile, tempWorkspace);

    ProcessResult result = bazel().shouldFail().build("//...");
    assertThat(
            findPattern(
                result,
                "WORKSPACE file can not be a symlink if incrementally updated directories are"
                    + " used."))
        .isTrue();
  }

  private void generateProject() throws IOException {
    writeProjectFile("BUILD.test", "BUILD");
    writeProjectFile("WORKSPACE.test", "WORKSPACE");
    writeProjectFile("bazelignore.test", ".bazelignore");
    writeProjectFile("package.json", "package.json");
    writeProjectFile("test_rule.bzl", "test_rule.bzl");
    writeProjectFile("use_node_modules.bzl", "use_node_modules.bzl");
  }

  private void writeProjectFile(String oldName, String newName) throws IOException {
    String text = ResourceFileLoader.loadResource(ManagedDirectoriesBlackBoxTest.class, oldName);
    assertThat(text).isNotNull();
    assertThat(text).isNotEmpty();
    context().write(newName, text);
  }

  private void checkProjectFiles() throws IOException {
    checkProjectFiles("0.2.0");
  }

  private void checkProjectFiles(String version) throws IOException {
    Path nodeModules = context().getWorkDir().resolve("node_modules");
    assertThat(nodeModules.toFile().exists()).isTrue();
    assertThat(nodeModules.toFile().isDirectory()).isTrue();

    Path exampleModule = nodeModules.resolve("example-module");
    assertThat(exampleModule.toFile().exists()).isTrue();
    assertThat(exampleModule.toFile().isDirectory()).isTrue();

    Path packageJson = exampleModule.resolve("package.json");
    assertThat(packageJson.toFile().exists()).isTrue();
    assertThat(packageJson.toFile().isDirectory()).isFalse();

    List<String> text = PathUtils.readFile(packageJson);
    assertThat(text.stream().anyMatch(s -> s.trim().equals("\"name\": \"example-module\",")))
        .isTrue();
    String versionString = String.format("\"version\": \"%s\"", version);
    assertThat(text.stream().anyMatch(s -> s.trim().equals(versionString))).isTrue();
  }

  private String getDebugId(BuilderRunner bazel) throws Exception {
    Path path = context().resolveExecRootPath(bazel, "external/generated_node_modules/debug_id");
    List<String> lines = PathUtils.readFile(path);
    assertThat(lines.size()).isEqualTo(1);
    return lines.get(0);
  }

  private ProcessResult buildExpectRepositoryRuleCalled() throws Exception {
    return buildExpectRepositoryRuleCalled(false, false);
  }

  private ProcessResult buildExpectRepositoryRuleCalled(boolean debug, boolean watchFs)
      throws Exception {
    BuilderRunner bazel = bazel(watchFs);
    if (debug) {
      bazel.enableDebug();
    }
    ProcessResult result = bazel.build("//...");
    buildSucceeded(result);
    debugIdShouldBeUpdated(bazel);
    return result;
  }

  private ProcessResult buildExpectRepositoryRuleNotCalled() throws Exception {
    return buildExpectRepositoryRuleNotCalled(false);
  }

  private ProcessResult buildExpectRepositoryRuleNotCalled(boolean debug) throws Exception {
    BuilderRunner bazel = bazel();
    if (debug) {
      bazel.enableDebug();
    }
    ProcessResult result = bazel.build("//...");
    buildSucceeded(result);
    debugIdShouldNotBeUpdated(bazel);
    return result;
  }

  private void debugIdShouldBeUpdated(BuilderRunner bazel) throws Exception {
    assertThat(getDebugId(bazel)).isEqualTo(String.valueOf(currentDebugId));
  }

  private void debugIdShouldNotBeUpdated(BuilderRunner bazel) throws Exception {
    assertThat(getDebugId(bazel)).isNotEqualTo(String.valueOf(currentDebugId));
  }

  private void buildSucceeded(ProcessResult result) {
    assertThat(findPattern(result, "INFO: Build completed successfully")).isTrue();
  }

  private void buildFailed(ProcessResult result) {
    assertThat(findPattern(result, "FAILED: Build did NOT complete successfully")).isTrue();
  }

  private boolean findPattern(ProcessResult result, String pattern) {
    String[] lines = result.errString().split("\n");
    return Arrays.stream(lines).anyMatch(s -> s.contains(pattern));
  }
}
