// Copyright (C) 2015 The Android Open Source Project
//
// 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.gerrit.acceptance.ssh;

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

import com.google.common.base.Splitter;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.UseSsh;
import com.google.gerrit.testutil.NoteDbMode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.eclipse.jgit.transport.PacketLineIn;
import org.eclipse.jgit.transport.PacketLineOut;
import org.eclipse.jgit.util.IO;
import org.junit.Before;
import org.junit.Test;

@NoHttpd
@UseSsh
public class UploadArchiveIT extends AbstractDaemonTest {

  @Before
  public void setUp() {
    // There is some Guice request scoping problem preventing this test from
    // passing in CHECK mode.
    assume().that(NoteDbMode.get()).isNotEqualTo(NoteDbMode.CHECK);
  }

  @Test
  @GerritConfig(name = "download.archive", value = "off")
  public void archiveFeatureOff() throws Exception {
    archiveNotPermitted();
  }

  @Test
  @GerritConfig(
      name = "download.archive",
      values = {"tar", "tbz2", "tgz", "txz"})
  public void zipFormatDisabled() throws Exception {
    archiveNotPermitted();
  }

  @Test
  public void zipFormat() throws Exception {
    PushOneCommit.Result r = createChange();
    String abbreviated = r.getCommit().abbreviate(8).name();
    String c = command(r, abbreviated);

    InputStream out =
        adminSshSession.exec2("git-upload-archive " + project.get(), argumentsToInputStream(c));

    // Wrap with PacketLineIn to read ACK bytes from output stream
    PacketLineIn in = new PacketLineIn(out);
    String tmp = in.readString();
    assertThat(tmp).isEqualTo("ACK");
    tmp = in.readString();

    // Skip length (4 bytes) + 1 byte
    // to position the output stream to the raw zip stream
    byte[] buffer = new byte[5];
    IO.readFully(out, buffer, 0, 5);
    Set<String> entryNames = new TreeSet<>();
    try (ZipArchiveInputStream zip = new ZipArchiveInputStream(out)) {
      ZipArchiveEntry zipEntry = zip.getNextZipEntry();
      while (zipEntry != null) {
        String name = zipEntry.getName();
        entryNames.add(name);
        zipEntry = zip.getNextZipEntry();
      }
    }

    assertThat(entryNames)
        .containsExactly(
            String.format("%s/", abbreviated),
            String.format("%s/%s", abbreviated, PushOneCommit.FILE_NAME))
        .inOrder();
  }

  private String command(PushOneCommit.Result r, String abbreviated) {
    String c =
        "-f=zip "
            + "-9 "
            + "--prefix="
            + abbreviated
            + "/ "
            + r.getCommit().name()
            + " "
            + PushOneCommit.FILE_NAME;
    return c;
  }

  private void archiveNotPermitted() throws Exception {
    PushOneCommit.Result r = createChange();
    String abbreviated = r.getCommit().abbreviate(8).name();
    String c = command(r, abbreviated);

    InputStream out =
        adminSshSession.exec2("git-upload-archive " + project.get(), argumentsToInputStream(c));

    // Wrap with PacketLineIn to read ACK bytes from output stream
    PacketLineIn in = new PacketLineIn(out);
    String tmp = in.readString();
    assertThat(tmp).isEqualTo("ACK");
    tmp = in.readString();
    tmp = in.readString();
    tmp = tmp.substring(1);
    assertThat(tmp).isEqualTo("fatal: upload-archive not permitted");
  }

  private InputStream argumentsToInputStream(String c) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    PacketLineOut pctOut = new PacketLineOut(out);
    for (String arg : Splitter.on(' ').split(c)) {
      pctOut.writeString("argument " + arg);
    }
    pctOut.end();
    return new ByteArrayInputStream(out.toByteArray());
  }
}
