// Copyright 2015 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.profiler;

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

import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.profiler.Profiler.ProfiledTaskKinds;
import com.google.devtools.build.lib.profiler.analysis.ProfileInfo;
import com.google.devtools.build.lib.profiler.chart.AggregatingChartCreator;
import com.google.devtools.build.lib.profiler.chart.Chart;
import com.google.devtools.build.lib.profiler.chart.ChartBar;
import com.google.devtools.build.lib.profiler.chart.ChartBarType;
import com.google.devtools.build.lib.profiler.chart.ChartColumn;
import com.google.devtools.build.lib.profiler.chart.ChartCreator;
import com.google.devtools.build.lib.profiler.chart.ChartLine;
import com.google.devtools.build.lib.profiler.chart.ChartRow;
import com.google.devtools.build.lib.profiler.chart.ChartVisitor;
import com.google.devtools.build.lib.profiler.chart.Color;
import com.google.devtools.build.lib.profiler.chart.DetailedChartCreator;
import com.google.devtools.build.lib.profiler.chart.HtmlChartVisitor;
import com.google.devtools.build.lib.testutil.FoundationTestCase;
import com.google.devtools.build.lib.testutil.Scratch;
import com.google.devtools.build.lib.testutil.Suite;
import com.google.devtools.build.lib.testutil.TestSpec;
import com.google.devtools.build.lib.vfs.Path;
import java.util.List;
import java.util.Locale;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for the profiler chart generation. */
@TestSpec(size = Suite.MEDIUM_TESTS)
@RunWith(JUnit4.class)
public class ProfilerChartTest extends FoundationTestCase {
  private static final int COMMON_CHART_TYPES = ProfilePhase.values().length;
  private static final int DETAILED_CHART_TYPES = ProfilerTask.values().length;
  private static final int AGGREGATED_CHART_TYPES = 4;
  private static final int AGGREGATED_CHART_NO_VFS_TYPES = 3;

  @Test
  public void testChartCreators() throws Exception {
    Runnable run = new Runnable() {
      @Override
      public void run() {
        Profiler.instance().startTask(ProfilerTask.ACTION, "action");
        Profiler.instance().completeTask(ProfilerTask.ACTION);
      }
    };
    int threads = 4; // there is one extra thread due due the event that finalizes the profiler
    ProfileInfo info = createProfileInfo(run, threads - 1);
    ChartCreator aggregatingCreator = new AggregatingChartCreator(info, true);
    Chart aggregatedChart = aggregatingCreator.create();
    assertThat(aggregatedChart.getRowCount()).isEqualTo(threads);
    assertThat(aggregatedChart.getSortedRows().get(0).getBars()).hasSize(1);

    ChartCreator detailedCreator = new DetailedChartCreator(info);
    Chart detailedChart = detailedCreator.create();
    assertThat(detailedChart.getSortedTypes()).hasSize(COMMON_CHART_TYPES + DETAILED_CHART_TYPES);
    assertThat(detailedChart.getRowCount()).isEqualTo(threads);
    assertThat(detailedChart.getSortedRows().get(0).getBars()).hasSize(1);
  }

  @Test
  public void testAggregatingChartCreator() throws Exception {
    Runnable run = new Runnable() {
      @Override
      public void run() {
        Profiler profiler = Profiler.instance();
        profiler.startTask(ProfilerTask.ACTION, "action"); // Stays
        task(profiler, ProfilerTask.REMOTE_EXECUTION, "remote execution"); // Removed
        task(profiler, ProfilerTask.ACTION_CHECK, "check"); // Removed
        task(profiler, ProfilerTask.ACTION_LOCK, "lock"); // Stays
        profiler.completeTask(ProfilerTask.ACTION);
        task(profiler, ProfilerTask.INFO, "info"); // Stays
        task(profiler, ProfilerTask.VFS_STAT, "stat"); // Stays, if showVFS
        task(profiler, ProfilerTask.WAIT, "wait"); // Stays
      }
    };
    ProfileInfo info = createProfileInfo(run, 1);

    ChartCreator aggregatingCreator = new AggregatingChartCreator(info, true);
    Chart aggregatedChart = aggregatingCreator.create();
    assertThat(aggregatedChart.getSortedTypes())
        .hasSize(COMMON_CHART_TYPES + AGGREGATED_CHART_TYPES);
    assertThat(aggregatedChart.getSortedRows().get(0).getBars()).hasSize(5);

    ChartCreator aggregatingNoVfsCreator = new AggregatingChartCreator(info, false);
    Chart aggregatedNoVfsChart = aggregatingNoVfsCreator.create();
    assertThat(aggregatedNoVfsChart.getSortedTypes())
        .hasSize(COMMON_CHART_TYPES + AGGREGATED_CHART_NO_VFS_TYPES);
    assertThat(aggregatedNoVfsChart.getSortedRows().get(0).getBars()).hasSize(4);

    ChartCreator detailedCreator = new DetailedChartCreator(info);
    Chart detailedChart = detailedCreator.create();
    assertThat(detailedChart.getSortedTypes())
        .hasSize(COMMON_CHART_TYPES + ProfilerTask.values().length);
    assertThat(detailedChart.getSortedRows().get(0).getBars()).hasSize(7);
  }

  @Test
  public void testChart() throws Exception {
    Chart chart = new Chart();

    ChartBarType type3 = chart.createType("name3", Color.GREEN);
    ChartBarType type2 = chart.createType("name2", Color.RED);
    ChartBarType type1 = chart.createType("name1", Color.BLACK);
    List<ChartBarType> types = chart.getSortedTypes();
    assertThat(types).hasSize(3);
    assertThat(types.get(0).getName()).isEqualTo(type1.getName());
    assertThat(types.get(0).getColor()).isEqualTo(type1.getColor());
    assertThat(types.get(1).getName()).isEqualTo(type2.getName());
    assertThat(types.get(1).getColor()).isEqualTo(type2.getColor());
    assertThat(types.get(2).getName()).isEqualTo(type3.getName());
    assertThat(types.get(2).getColor()).isEqualTo(type3.getColor());

    assertThat(chart.lookUpType("name3")).isSameAs(type3);
    assertThat(chart.lookUpType("name2")).isSameAs(type2);
    assertThat(chart.lookUpType("name1")).isSameAs(type1);

    assertThat(chart.lookUpType("wergl")).isSameAs(Chart.UNKNOWN_TYPE);
    types = chart.getSortedTypes();
    assertThat(types).hasSize(4);

    chart.addBar(1, 2, 3, type1, "label1");
    chart.addBar(2, 3, 4, type2, "label2");
    chart.addBar(2, 4, 5, type3, "label3");
    chart.addBar(3, 3, 4, type2, "label4");
    chart.addBar(3, 4, 5, type3, "label5");
    chart.addBar(3, 5, 6, type3, "label6");

    assertThat(chart.getMaxStop()).isEqualTo(6);
    assertThat(chart.getRowCount()).isEqualTo(3);

    List<ChartRow> rows = chart.getSortedRows();
    assertThat(rows).hasSize(3);
    assertThat(rows.get(0).getBars()).hasSize(1);
    assertThat(rows.get(1).getBars()).hasSize(2);
    assertThat(rows.get(2).getBars()).hasSize(3);

    ChartBar bar = rows.get(0).getBars().get(0);
    assertThat(bar.getStart()).isEqualTo(2);
    assertThat(bar.getStop()).isEqualTo(3);
    assertThat(bar.getType()).isSameAs(type1);
    assertThat(bar.getLabel()).isEqualTo("label1");
  }

  @Test
  public void testChartRows() throws Exception {
    ChartRow row1 = new ChartRow("1", 0);
    ChartRow row2 = new ChartRow("2", 1);
    ChartRow row3 = new ChartRow("3", 1);

    assertThat(row1.getId()).isEqualTo("1");
    assertThat(row1.getIndex()).isEqualTo(0);

    assertThat(row1.compareTo(row2)).isEqualTo(-1);
    assertThat(row2.compareTo(row1)).isEqualTo(1);
    assertThat(row2.compareTo(row3)).isEqualTo(0);

    row1.addBar(new ChartBar(row1, 1, 2, new ChartBarType("name1", Color.BLACK), false, "label1"));
    row1.addBar(new ChartBar(row1, 2, 3, new ChartBarType("name2", Color.RED), false, "label2"));

    assertThat(row1.getBars()).hasSize(2);
    assertThat(row1.getBars().get(0).getLabel()).isEqualTo("label1");
    assertThat(row1.getBars().get(1).getLabel()).isEqualTo("label2");
  }

  @Test
  public void testChartBarTypes() throws Exception {
    ChartBarType type1 = new ChartBarType("name1", Color.BLACK);
    ChartBarType type2 = new ChartBarType("name2", Color.RED);
    ChartBarType type3 = new ChartBarType("name2", Color.GREEN);

    assertThat(type1.compareTo(type2)).isEqualTo(-1);
    assertThat(type2.compareTo(type1)).isEqualTo(1);
    assertThat(type2.compareTo(type3)).isEqualTo(0);

    assertThat(type2).isEqualTo(type3);
    assertThat(type1.equals(type3)).isFalse();
    assertThat(type1.equals(type2)).isFalse();

    assertThat(type2.hashCode()).isEqualTo(type3.hashCode());
    assertThat(type1.hashCode() == type2.hashCode()).isFalse();
    assertThat(type1.hashCode() == type3.hashCode()).isFalse();
  }

  @Test
  public void testChartBar() throws Exception {
    ChartRow row1 = new ChartRow("1", 0);
    ChartBarType type = new ChartBarType("name1", Color.BLACK);
    ChartBar bar1 = new ChartBar(row1, 1, 2, type, false, "label1");
    assertThat(bar1.getRow()).isEqualTo(row1);
    assertThat(bar1.getStart()).isEqualTo(1);
    assertThat(bar1.getStop()).isEqualTo(2);
    assertThat(bar1.getType()).isSameAs(type);
    assertThat(bar1.getLabel()).isEqualTo("label1");
  }

  @Test
  public void testVisitor() throws Exception {
    Chart chart = new Chart();
    ChartBarType type3 = chart.createType("name3", Color.GREEN);
    ChartBarType type2 = chart.createType("name2", Color.RED);
    ChartBarType type1 = chart.createType("name1", Color.BLACK);
    chart.addBar(1, 2, 3, type1, "label1");
    chart.addBar(2, 3, 4, type2, "label2");
    chart.addBar(2, 4, 5, type3, "label3");
    chart.addBar(3, 3, 4, type2, "label4");
    chart.addBar(3, 4, 5, type3, "label5");
    chart.addBar(3, 5, 6, type3, "label6");

    TestingChartVisitor visitor = new TestingChartVisitor();
    chart.accept(visitor);
    assertThat(visitor.beginChartCount).isEqualTo(1);
    assertThat(visitor.endChartCount).isEqualTo(1);
    assertThat(visitor.rowCount).isEqualTo(3);
    assertThat(visitor.barCount).isEqualTo(6);
    assertThat(visitor.columnCount).isEqualTo(0);
    assertThat(visitor.lineCount).isEqualTo(0);
  }

  @Test
  public void testHtmlChartVisitorFormatColor() {
    Locale defaultLocale = Locale.getDefault();

    Locale.setDefault(Locale.GERMANY);
    String black = HtmlChartVisitor.formatColor(Color.GRAY);
    String[] grayComponents = black.split(",");
    assertThat(grayComponents.length).isEqualTo(4);

    Locale.setDefault(defaultLocale);
  }

  private ProfileInfo createProfileInfo(Runnable runnable, int noOfRows) throws Exception {
    Scratch scratch = new Scratch();
    Path cacheDir = scratch.dir("/tmp");
    Path cacheFile = cacheDir.getRelative("profile1.dat");
    Profiler profiler = Profiler.instance();
    profiler.start(ProfiledTaskKinds.ALL, cacheFile.getOutputStream(), "basic test", false,
        BlazeClock.instance(), BlazeClock.instance().nanoTime());

    // Write from multiple threads to generate multiple rows in the chart.
    for (int i = 0; i < noOfRows; i++) {
      Thread t = new Thread(runnable);
      t.start();
      t.join();
    }

    profiler.stop();
    return ProfileInfo.loadProfile(cacheFile);
  }

  private void task(final Profiler profiler, ProfilerTask task, String name) {
    profiler.startTask(task, name);
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // ignore
    }
    profiler.completeTask(task);
  }

  private static final class TestingChartVisitor implements ChartVisitor {
    private int rowCount;
    private int endChartCount;
    private int barCount;
    private int beginChartCount;
    private int columnCount;
    private int lineCount;

    @Override
    public void visit(Chart chart) {
      beginChartCount++;
    }

    @Override
    public void endVisit(Chart chart) {
      endChartCount++;
    }

    @Override
    public void visit(ChartRow chartRow) {
      rowCount++;
    }

    @Override
    public void visit(ChartBar chartBar) {
      barCount++;
    }

    @Override
    public void visit(ChartColumn chartColumn) {
      columnCount++;
    }

    @Override
    public void visit(ChartLine chartLine) {
      lineCount++;
    }
  }
}
