// Copyright 2017 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.shell;

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

import com.google.devtools.build.lib.vfs.Path;
import java.io.IOException;
import java.time.Duration;
import java.util.List;
import java.util.Optional;

/**
 * Utilities to assist with testing execution statistics generated via the {@code process-wrapper}
 * and {@code linux-sandbox} tools.
 */
public class ExecutionStatisticsTestUtil {
  /**
   * Executes a command and checks that the execution statistics timing info for that command
   * satisfy certain constraints.
   *
   * @param userTimeToSpend a lower bound for how much CPU user execution time was expected
   * @param systemTimeToSpend a lower bound for how much CPU system execution time was expected
   * @param fullCommandLine the command to execute, including any wrappers used (like linux-sandbox)
   * @param statisticsFilePath where the execution statistics file will be generated (to be read)
   */
  public static void executeCommandAndCheckStatisticsAboutCpuTimeSpent(
      Duration userTimeToSpend,
      Duration systemTimeToSpend,
      List<String> fullCommandLine,
      Path statisticsFilePath)
      throws CommandException, IOException {
    Duration userTimeLowerBound = userTimeToSpend;
    Duration userTimeUpperBound = userTimeToSpend.plusSeconds(9);
    Duration systemTimeLowerBound = systemTimeToSpend;

    // TODO(b/110456205) This check fails under very heavy load, investigate why and re-enable it
    // Duration systemTimeUpperBound = systemTimeToSpend.plusSeconds(9);

    Command command = new Command(fullCommandLine.toArray(new String[0]));
    CommandResult commandResult = command.execute();
    assertThat(commandResult.getTerminationStatus().success()).isTrue();

    Optional<ExecutionStatistics.ResourceUsage> resourceUsage =
        ExecutionStatistics.getResourceUsage(statisticsFilePath);
    assertThat(resourceUsage).isPresent();

    Duration userTime = resourceUsage.get().getUserExecutionTime();
    assertThat(userTime).isAtLeast(userTimeLowerBound);
    assertThat(userTime).isAtMost(userTimeUpperBound);

    Duration systemTime = resourceUsage.get().getSystemExecutionTime();
    assertThat(systemTime).isAtLeast(systemTimeLowerBound);

    // TODO(b/110456205) This check fails under very heavy load, investigate why and re-enable it
    // assertThat(systemTime).isAtMost(systemTimeUpperBound);
  }
}
