// Copyright 2021 Google LLC. 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.gitiles;

import static com.google.common.truth.Truth.assertThat;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import static javax.servlet.http.HttpServletResponse.SC_OK;

import com.google.common.base.Strings;
import com.google.common.net.HttpHeaders;
import java.util.Optional;
import javax.annotation.Nullable;
import org.eclipse.jgit.internal.storage.dfs.DfsRepository;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for BranchRedirect. */
@RunWith(JUnit4.class)
public class BranchRedirectTest {
  private static final String MASTER = "refs/heads/master";
  private static final String MAIN = "refs/heads/main";
  private static final String DEVELOP = "refs/heads/develop";
  private static final String FOO = "refs/heads/foo";
  private static final String BAR = "refs/heads/bar";
  private static final String ORIGIN = "http://localhost";
  private static final String QUERY_STRING_HTML = "format=html";
  private static final String QUERY_STRING_JSON = "format=json";

  private TestRepository<DfsRepository> repo;
  private GitilesServlet servlet;

  @Before
  public void setUp() throws Exception {
    repo = new TestRepository<>(new InMemoryRepository(new DfsRepositoryDescription("repo")));
    BranchRedirect branchRedirect =
        new BranchRedirect() {
          @Override
          protected Optional<String> getRedirectBranch(Repository repo, String sourceBranch) {
            if (MASTER.equals(toFullBranchName(sourceBranch))) {
              return Optional.of(MAIN);
            }
            if (FOO.equals(toFullBranchName(sourceBranch))) {
              return Optional.of(BAR);
            }
            return Optional.empty();
          }
        };
    servlet = TestGitilesServlet.create(repo, new GitwebRedirectFilter(), branchRedirect);
  }

  @Test
  public void show_withoutRedirect() throws Exception {
    repo.branch("develop").commit().add("foo", "contents").create();

    String path = "/repo/+/refs/heads/develop/foo";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
  }

  @Test
  public void show_withRedirect() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+/refs/heads/master/foo";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getActualBodyString()).contains("repo/+/refs/heads/main/foo");
    assertThat(res.getActualBodyString()).doesNotContain("repo/+/refs/heads/master/foo");
  }

  @Test
  public void show_withRedirect_onDefaultFormatType() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+/refs/heads/master/foo";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, null);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("repo/+/refs/heads/main/foo");
    assertThat(res.getActualBodyString()).doesNotContain("repo/+/refs/heads/master/foo");
  }

  @Test
  public void show_withRedirect_usingShortRefInUrl() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+/master/foo";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("repo/+/refs/heads/main/foo");
    assertThat(res.getActualBodyString()).doesNotContain("repo/+/master/foo");
  }

  @Test
  public void show_onAutomationRequest() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+/refs/heads/master/foo";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_JSON);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("\"revision\": \"refs/heads/master\"");
    assertThat(res.getActualBodyString()).contains("\"path\": \"foo\"");
  }

  @Test
  public void showParent_withRedirect() throws Exception {
    RevCommit parent = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MASTER).commit().add("bar", "contents").parent(parent).create();
    repo.branch(MAIN).commit().parent(parent).create();

    String path = "/repo/+/refs/heads/master^";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    // It is resolved to the object id by ViewFilter.
    assertThat(res.getStatus()).isEqualTo(SC_MOVED_TEMPORARILY);
    assertThat(res.getHeader(HttpHeaders.LOCATION))
        .isEqualTo("/b/repo/+/" + parent.toObjectId().name() + "?format=html");
  }

  @Test
  public void diff_withRedirect_onSingleBranch() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();
    repo.branch(DEVELOP).commit().add("foo", "contents").create();

    String path = "/repo/+/refs/heads/master..refs/heads/develop";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString())
        .contains("/b/repo/+/refs/heads/main..refs/heads/develop/?format=html");
  }

  @Test
  public void diff_withRedirect_onBothBranch() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();
    RevCommit foo = repo.branch(FOO).commit().add("foo", "contents").create();
    repo.branch(BAR).commit().parent(foo).create();

    String path = "/repo/+/refs/heads/foo..refs/heads/master";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString())
        .contains("/b/repo/+/refs/heads/bar..refs/heads/main/?format=html");
  }

  @Test
  public void diff_withRedirect() throws Exception {
    RevCommit master = repo.branch(MASTER).commit().add("foo", "contents").create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+diff/refs/heads/master^!";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("/b/repo/+/refs/heads/main%5E%21/?format=html");
  }

  @Test
  public void log_withRedirect() throws Exception {
    repo.branch(MASTER).commit().add("foo", "contents").create();
    RevCommit main = repo.branch(MAIN).commit().create();

    String path = "/repo/+log/refs/heads/master";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("Log - refs/heads/main");
    assertThat(res.getActualBodyString()).contains("/b/repo/+/" + main.toObjectId().getName());
  }

  @Test
  public void diff_withGrandParent_redirect() throws Exception {
    RevCommit parent1 = repo.branch(MASTER).commit().add("foo", "contents").create();
    RevCommit parent2 =
        repo.branch(MASTER).commit().add("bar", "contents").parent(parent1).create();
    RevCommit master = repo.branch(MASTER).commit().add("bar", "contents").parent(parent2).create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+diff/refs/heads/master^^..refs/heads/master";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString())
        .contains("/b/repo/+/refs/heads/main%5E%5E..refs/heads/main/?format=html");
  }

  @Test
  public void diff_withRelativeParent_redirect() throws Exception {
    RevCommit parent1 = repo.branch(MASTER).commit().add("foo", "contents").create();
    RevCommit parent2 =
        repo.branch(MASTER).commit().add("bar", "contents").parent(parent1).create();
    RevCommit master = repo.branch(MASTER).commit().add("bar", "contents").parent(parent2).create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+diff/refs/heads/master~1..refs/heads/master";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString()).contains("/b/repo/+/refs/heads/main%5E%21/?format=html");
  }

  @Test
  public void diff_withRelativeGrandParent_redirect() throws Exception {
    RevCommit parent1 = repo.branch(MASTER).commit().add("foo", "contents").create();
    RevCommit parent2 =
        repo.branch(MASTER).commit().add("bar", "contents").parent(parent1).create();
    RevCommit master = repo.branch(MASTER).commit().add("bar", "contents").parent(parent2).create();
    repo.branch(MAIN).commit().parent(master).create();

    String path = "/repo/+diff/refs/heads/master~2..refs/heads/master";
    FakeHttpServletRequest req = newHttpRequest(path, ORIGIN, QUERY_STRING_HTML);
    FakeHttpServletResponse res = new FakeHttpServletResponse();

    servlet.service(req, res);
    assertThat(res.getStatus()).isEqualTo(SC_OK);
    assertThat(res.getActualBodyString())
        .contains("/b/repo/+/refs/heads/main%7E2..refs/heads/main/?format=html");
  }

  private static String toFullBranchName(String sourceBranch) {
    if (sourceBranch.startsWith(Constants.R_REFS)) {
      return sourceBranch;
    }
    return Constants.R_HEADS + sourceBranch;
  }

  private static FakeHttpServletRequest newHttpRequest(
      String path, String origin, @Nullable String queryString) {
    FakeHttpServletRequest req = FakeHttpServletRequest.newRequest();
    req.setHeader(HttpHeaders.ORIGIN, origin);
    req.setPathInfo(path);
    if (!Strings.isNullOrEmpty(queryString)) {
      req.setQueryString(queryString);
    }
    return req;
  }
}
