Package org.ngrinder.perftest.controller

Source Code of org.ngrinder.perftest.controller.PerfTestController

/*
* 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 org.ngrinder.perftest.controller;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.grinder.util.LogCompressUtils;
import net.grinder.util.Pair;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.mutable.MutableInt;
import org.ngrinder.agent.service.AgentManagerService;
import org.ngrinder.common.constant.ControllerConstants;
import org.ngrinder.common.controller.BaseController;
import org.ngrinder.common.controller.RestAPI;
import org.ngrinder.common.util.DateUtils;
import org.ngrinder.common.util.FileDownloadUtils;
import org.ngrinder.infra.config.Config;
import org.ngrinder.infra.logger.CoreLogger;
import org.ngrinder.infra.spring.RemainedPath;
import org.ngrinder.model.*;
import org.ngrinder.perftest.service.AgentManager;
import org.ngrinder.perftest.service.PerfTestService;
import org.ngrinder.perftest.service.TagService;
import org.ngrinder.region.service.RegionService;
import org.ngrinder.script.handler.ScriptHandlerFactory;
import org.ngrinder.script.model.FileCategory;
import org.ngrinder.script.model.FileEntry;
import org.ngrinder.script.service.FileEntryService;
import org.ngrinder.user.service.UserService;
import org.python.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefaults;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.*;

import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
import static org.apache.commons.lang.StringUtils.trimToEmpty;
import static org.ngrinder.common.util.CollectionUtils.buildMap;
import static org.ngrinder.common.util.CollectionUtils.newHashMap;
import static org.ngrinder.common.util.ExceptionUtils.processException;
import static org.ngrinder.common.util.ObjectUtils.defaultIfNull;
import static org.ngrinder.common.util.Preconditions.*;

/**
* Performance Test Controller.
*
* @author Mavlarn
* @author JunHo Yoon
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@Controller
@RequestMapping("/perftest")
public class PerfTestController extends BaseController {

  @Autowired
  private PerfTestService perfTestService;

  @Autowired
  private FileEntryService fileEntryService;

  @Autowired
  private AgentManager agentManager;

  @Autowired
  private AgentManagerService agentManagerService;

  @Autowired
  private TagService tagService;

  @Autowired
  private ScriptHandlerFactory scriptHandlerFactory;

  @Autowired
  private UserService userService;

  @Autowired
  private RegionService regionService;

  private Gson fileEntryGson;

  /**
   * Initialize.
   */
  @PostConstruct
  public void init() {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(FileEntry.class, new FileEntry.FileEntrySerializer());
    fileEntryGson = gsonBuilder.create();
  }

  /**
   * Get the perf test lists.
   *
   * @param user        user
   * @param query       query string to search the perf test
   * @param tag         tag
   * @param queryFilter "F" means get only finished, "S" means get only scheduled tests.
   * @param pageable    page
   * @param model       modelMap
   * @return perftest/list
   */
  @RequestMapping({"/list", "/", ""})
  public String getAll(User user, @RequestParam(required = false) String query,
                       @RequestParam(required = false) String tag, @RequestParam(required = false) String queryFilter,
                       @PageableDefaults Pageable pageable, ModelMap model) {
    pageable = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(),
        defaultIfNull(pageable.getSort(),
            new Sort(Direction.DESC, "lastModifiedDate")));
    Page<PerfTest> tests = perfTestService.getPagedAll(user, query, tag, queryFilter, pageable);
    annotateDateMarker(tests);
    model.addAttribute("tag", tag);
    model.addAttribute("availTags", tagService.getAllTagStrings(user, StringUtils.EMPTY));
    model.addAttribute("testListPage", tests);
    model.addAttribute("queryFilter", queryFilter);
    model.addAttribute("query", query);
    putPageIntoModelMap(model, pageable);
    return "perftest/list";
  }

  private void annotateDateMarker(Page<PerfTest> tests) {
    TimeZone userTZ = TimeZone.getTimeZone(getCurrentUser().getTimeZone());
    Calendar userToday = Calendar.getInstance(userTZ);
    Calendar userYesterday = Calendar.getInstance(userTZ);
    userYesterday.add(Calendar.DATE, -1);
    for (PerfTest test : tests) {
      Calendar localedModified = Calendar.getInstance(userTZ);
      localedModified.setTime(DateUtils.convertToUserDate(getCurrentUser().getTimeZone(),
          test.getLastModifiedDate()));
      if (org.apache.commons.lang.time.DateUtils.isSameDay(userToday, localedModified)) {
        test.setDateString("today");
      } else if (org.apache.commons.lang.time.DateUtils.isSameDay(userYesterday, localedModified)) {
        test.setDateString("yesterday");
      } else {
        test.setDateString("earlier");
      }
    }
  }

  /**
   * Open the new perf test creation form.
   *
   * @param user  user
   * @param model model
   * @return "perftest/detail"
   */
  @RequestMapping("/new")
  public String openForm(User user, ModelMap model) {
    return getOne(user, null, model);
  }

  /**
   * Get the perf test detail on the given perf test id.
   *
   * @param user  user
   * @param id    perf test id
   * @param model model
   * @return perftest/detail
   */
  @RequestMapping("/{id}")
  public String getOne(User user, @PathVariable("id") Long id, ModelMap model) {
    PerfTest test = null;
    if (id != null) {
      test = getOneWithPermissionCheck(user, id, true);
    }

    if (test == null) {
      test = new PerfTest(user);
      test.init();
    }

    model.addAttribute(PARAM_TEST, test);
    // Retrieve the agent count map based on create user, if the test is
    // created by the others.
    user = test.getCreatedUser() != null ? test.getCreatedUser() : user;

    Map<String, MutableInt> agentCountMap = agentManagerService.getAvailableAgentCountMap(user);
    model.addAttribute(PARAM_REGION_AGENT_COUNT_MAP, agentCountMap);
    model.addAttribute(PARAM_REGION_LIST, regionService.getAllVisibleRegionNames());
    model.addAttribute(PARAM_PROCESS_THREAD_POLICY_SCRIPT, perfTestService.getProcessAndThreadPolicyScript());
    addDefaultAttributeOnModel(model);
    return "perftest/detail";
  }

  private ArrayList<String> getRegions(Map<String, MutableInt> agentCountMap) {
    ArrayList<String> regions = new ArrayList<String>(agentCountMap.keySet());
    Collections.sort(regions);
    return regions;
  }


  /**
   * Search tags based on the given query.
   *
   * @param user  user to search
   * @param query query string
   * @return found tag list in json
   */
  @RequestMapping("/search_tag")
  public HttpEntity<String> searchTag(User user, @RequestParam(required = false) String query) {
    List<String> allStrings = tagService.getAllTagStrings(user, query);
    if (StringUtils.isNotBlank(query)) {
      allStrings.add(query);
    }
    return toJsonHttpEntity(allStrings);
  }

  /**
   * Add the various default configuration values on the model.
   *
   * @param model model to which put the default values
   */
  public void addDefaultAttributeOnModel(ModelMap model) {
    model.addAttribute(PARAM_AVAILABLE_RAMP_UP_TYPE, RampUp.values());
    model.addAttribute(PARAM_MAX_VUSER_PER_AGENT, agentManager.getMaxVuserPerAgent());
    model.addAttribute(PARAM_MAX_RUN_COUNT, agentManager.getMaxRunCount());
    model.addAttribute(PARAM_SECURITY_MODE, getConfig().isSecurityEnabled());
    model.addAttribute(PARAM_MAX_RUN_HOUR, agentManager.getMaxRunHour());
    model.addAttribute(PARAM_SAFE_FILE_DISTRIBUTION,
        getConfig().getControllerProperties().getPropertyBoolean(ControllerConstants.PROP_CONTROLLER_SAFE_DIST));
    String timeZone = getCurrentUser().getTimeZone();
    int offset;
    if (StringUtils.isNotBlank(timeZone)) {
      offset = TimeZone.getTimeZone(timeZone).getOffset(System.currentTimeMillis());
    } else {
      offset = TimeZone.getDefault().getOffset(System.currentTimeMillis());
    }
    model.addAttribute(PARAM_TIMEZONE_OFFSET, offset);
  }

  /**
   * Get the perf test creation form for quickStart.
   *
   * @param user       user
   * @param urlString  URL string to be tested.
   * @param scriptType scriptType
   * @param model      model
   * @return perftest/detail
   */
  @RequestMapping("/quickstart")
  public String getQuickStart(User user,
                              @RequestParam(value = "url", required = true) String urlString,
                              @RequestParam(value = "scriptType", required = true) String scriptType,
                              ModelMap model) {
    URL url = checkValidURL(urlString);
    FileEntry newEntry = fileEntryService.prepareNewEntryForQuickTest(user, urlString,
        scriptHandlerFactory.getHandler(scriptType));
    model.addAttribute(PARAM_QUICK_SCRIPT, newEntry.getPath());
    model.addAttribute(PARAM_QUICK_SCRIPT_REVISION, newEntry.getRevision());
    model.addAttribute(PARAM_TEST, createPerfTestFromQuickStart(user, "Test for " + url.getHost(), url.getHost()));
    Map<String, MutableInt> agentCountMap = agentManagerService.getAvailableAgentCountMap(user);
    model.addAttribute(PARAM_REGION_AGENT_COUNT_MAP, agentCountMap);
    model.addAttribute(PARAM_REGION_LIST, getRegions(agentCountMap));
    addDefaultAttributeOnModel(model);
    model.addAttribute(PARAM_PROCESS_THREAD_POLICY_SCRIPT, perfTestService.getProcessAndThreadPolicyScript());
    return "perftest/detail";
  }

  /**
   * Create a new test from quick start mode.
   *
   * @param user       user
   * @param testName   test name
   * @param targetHost target host
   * @return test    {@link PerfTest}
   */
  private PerfTest createPerfTestFromQuickStart(User user, String testName, String targetHost) {
    PerfTest test = new PerfTest(user);
    test.init();
    test.setTestName(testName);
    test.setTargetHosts(targetHost);
    return test;
  }

  /**
   * Create a new test or cloneTo a current test.
   *
   * @param user     user
   * @param perfTest {@link PerfTest}
   * @param isClone  true if cloneTo
   * @param model    model
   * @return redirect:/perftest/list
   */
  @RequestMapping(value = "/new", method = RequestMethod.POST)
  public String saveOne(User user, PerfTest perfTest,
                        @RequestParam(value = "isClone", required = false, defaultValue = "false") boolean isClone, ModelMap model) {

    validate(user, null, perfTest);
    // Point to the head revision
    perfTest.setTestName(StringUtils.trimToEmpty(perfTest.getTestName()));
    perfTest.setScriptRevision(-1L);
    perfTest.prepare(isClone);
    perfTest = perfTestService.save(user, perfTest);
    model.clear();
    if (perfTest.getStatus() == Status.SAVED || perfTest.getScheduledTime() != null) {
      return "redirect:/perftest/list";
    } else {
      return "redirect:/perftest/" + perfTest.getId();
    }
  }

  @SuppressWarnings("ConstantConditions")
  private void validate(User user, PerfTest oldOne, PerfTest newOne) {
    if (oldOne == null) {
      oldOne = new PerfTest();
      oldOne.init();
    }
    newOne = oldOne.merge(newOne);
    checkNotEmpty(newOne.getTestName(), "testName should be provided");
    checkArgument(newOne.getStatus().equals(Status.READY) || newOne.getStatus().equals(Status.SAVED),
        "status only allows SAVE or READY");
    if (newOne.isThresholdRunCount()) {
      final Integer runCount = newOne.getRunCount();
      checkArgument(runCount > 0 && runCount <= agentManager
          .getMaxRunCount(),
          "runCount should be equal to or less than %s", agentManager.getMaxRunCount());
    } else {
      final Long duration = newOne.getDuration();
      checkArgument(duration > 0 && duration <= (((long) agentManager.getMaxRunHour()) *
          3600000L),
          "duration should be equal to or less than %s", agentManager.getMaxRunHour());
    }
    Map<String, MutableInt> agentCountMap = agentManagerService.getAvailableAgentCountMap(user);
    MutableInt agentCountObj = agentCountMap.get(isClustered() ? newOne.getRegion() : Config.NONE_REGION);
    checkNotNull(agentCountObj, "region should be within current region list");
    int agentMaxCount = agentCountObj.intValue();
    checkArgument(newOne.getAgentCount() <= agentMaxCount, "test agent should be equal to or less than %s",
        agentMaxCount);
    if (newOne.getStatus().equals(Status.READY)) {
      checkArgument(newOne.getAgentCount() >= 1, "agentCount should be more than 1 when it's READY status.");
    }

    checkArgument(newOne.getVuserPerAgent() <= agentManager.getMaxVuserPerAgent(),
        "vuserPerAgent should be equal to or less than %s", agentManager.getMaxVuserPerAgent());
    if (getConfig().isSecurityEnabled()) {
      checkArgument(StringUtils.isNotEmpty(newOne.getTargetHosts()),
          "targetHosts should be provided when security mode is enabled");
    }
    if (newOne.getStatus() != Status.SAVED) {
      checkArgument(StringUtils.isNotBlank(newOne.getScriptName()), "scriptName should be provided.");
    }
    checkArgument(newOne.getVuserPerAgent() == newOne.getProcesses() * newOne.getThreads(),
        "vuserPerAgent should be equal to (processes * threads)");
  }

  /**
   * Leave the comment on the perf test.
   *
   * @param id          testId
   * @param user        user
   * @param testComment test comment
   * @param tagString   tagString
   * @return JSON
   */
  @RequestMapping(value = "/{id}/leave_comment", method = RequestMethod.POST)
  @ResponseBody
  public String leaveComment(User user, @PathVariable("id") Long id, @RequestParam("testComment") String testComment,
                             @RequestParam(value = "tagString", required = false) String tagString) {
    perfTestService.addCommentOn(user, id, testComment, tagString);
    return returnSuccess();
  }


  private Long[] convertString2Long(String ids) {
    String[] numbers = StringUtils.split(ids, ",");
    Long[] id = new Long[numbers.length];
    int i = 0;
    for (String each : numbers) {
      id[i++] = NumberUtils.toLong(each, 0);
    }
    return id;
  }

  private List<Map<String, Object>> getStatus(List<PerfTest> perfTests) {
    List<Map<String, Object>> statuses = newArrayList();
    for (PerfTest each : perfTests) {
      Map<String, Object> result = newHashMap();
      result.put("id", each.getId());
      result.put("status_id", each.getStatus());
      result.put("status_type", each.getStatus());
      result.put("name", getMessages(each.getStatus().getSpringMessageKey()));
      result.put("icon", each.getStatus().getIconName());
      result.put("message",
          StringUtils.replace(each.getProgressMessage() + "\n<b>" + each.getLastProgressMessage() + "</b>\n"
              + each.getLastModifiedDateToStr(), "\n", "<br/>"));
      result.put("deletable", each.getStatus().isDeletable());
      result.put("stoppable", each.getStatus().isStoppable());
      result.put("reportable", each.getStatus().isReportable());
      statuses.add(result);
    }
    return statuses;
  }


  /**
   * Delete the perf tests having given IDs.
   *
   * @param user user
   * @param ids  comma operated IDs
   * @return success json messages if succeeded.
   */
  @RestAPI
  @RequestMapping(value = "/api", method = RequestMethod.DELETE)
  public HttpEntity<String> delete(User user, @RequestParam(value = "ids", defaultValue = "") String ids) {
    for (String idStr : StringUtils.split(ids, ",")) {
      perfTestService.delete(user, NumberUtils.toLong(idStr, 0));
    }
    return successJsonHttpEntity();
  }

  /**
   * Stop the perf tests having given IDs.
   *
   * @param user user
   * @param ids  comma separated perf test IDs
   * @return success json if succeeded.
   */
  @RestAPI
  @RequestMapping(value = "/api", params = "action=stop", method = RequestMethod.PUT)
  public HttpEntity<String> stop(User user, @RequestParam(value = "ids", defaultValue = "") String ids) {
    for (String idStr : StringUtils.split(ids, ",")) {
      perfTestService.stop(user, NumberUtils.toLong(idStr, 0));
    }
    return successJsonHttpEntity();
  }

  /**
   * Filter out please_modify_this.com from hosts string.
   *
   * @param originalString original string
   * @return filtered string
   */
  private String filterHostString(String originalString) {
    List<String> hosts = newArrayList();
    for (String each : StringUtils.split(StringUtils.trimToEmpty(originalString), ",")) {
      if (!each.contains("please_modify_this.com")) {
        hosts.add(each);
      }
    }
    return StringUtils.join(hosts, ",");
  }


  private Map<String, Object> getPerfGraphData(Long id, String[] dataTypes, boolean onlyTotal, int imgWidth) {
    final PerfTest test = perfTestService.getOne(id);
    int interval = perfTestService.getReportDataInterval(id, dataTypes[0], imgWidth);
    Map<String, Object> resultMap = Maps.newHashMap();
    for (String each : dataTypes) {
      Pair<ArrayList<String>, ArrayList<String>> tpsResult = perfTestService.getReportData(id, each, onlyTotal, interval);
      Map<String, Object> dataMap = Maps.newHashMap();
      dataMap.put("labels", tpsResult.getFirst());
      dataMap.put("data", tpsResult.getSecond());
      resultMap.put(StringUtils.replaceChars(each, "()", ""), dataMap);
    }
    resultMap.put(PARAM_TEST_CHART_INTERVAL, interval * test.getSamplingInterval());
    return resultMap;
  }


  /**
   * Get the running division in perftest configuration page.
   *
   * @param user  user
   * @param model model
   * @param id    test id
   * @return perftest/running
   */
  @RequestMapping(value = "{id}/running_div")
  public String getReportSection(User user, ModelMap model, @PathVariable long id) {
    PerfTest test = getOneWithPermissionCheck(user, id, false);
    model.addAttribute(PARAM_TEST, test);
    return "perftest/running";
  }


  /**
   * Get the basic report content in perftest configuration page.
   * <p/>
   * This method returns the appropriate points based on the given imgWidth.
   *
   * @param user     user
   * @param model    model
   * @param id       test id
   * @param imgWidth image width
   * @return perftest/basic_report
   */
  @RequestMapping(value = "{id}/basic_report")
  public String getReportSection(User user, ModelMap model, @PathVariable long id, @RequestParam int imgWidth) {
    PerfTest test = getOneWithPermissionCheck(user, id, false);
    int interval = perfTestService.getReportDataInterval(id, "TPS", imgWidth);
    model.addAttribute(PARAM_LOG_LIST, perfTestService.getLogFiles(id));
    model.addAttribute(PARAM_TEST_CHART_INTERVAL, interval * test.getSamplingInterval());
    model.addAttribute(PARAM_TEST, test);
    model.addAttribute(PARAM_TPS, perfTestService.getSingleReportDataAsJson(id, "TPS", interval));
    return "perftest/basic_report";
  }

  /**
   * Download the CSV report for the given perf test id.
   *
   * @param user     user
   * @param id       test id
   * @param response response
   */
  @RequestMapping(value = "/{id}/download_csv")
  public void downloadCSV(User user, @PathVariable("id") long id, HttpServletResponse response) {
    PerfTest test = getOneWithPermissionCheck(user, id, false);
    File targetFile = perfTestService.getCsvReportFile(test);
    checkState(targetFile.exists(), "File %s doesn't exist!", targetFile.getName());
    FileDownloadUtils.downloadFile(response, targetFile);
  }

  /**
   * Download logs for the perf test having the given id.
   *
   * @param user     user
   * @param id       test id
   * @param path     path in the log folder
   * @param response response
   */
  @RequestMapping(value = "/{id}/download_log/**")
  public void downloadLog(User user, @PathVariable("id") long id, @RemainedPath String path,
                          HttpServletResponse response) {
    getOneWithPermissionCheck(user, id, false);
    File targetFile = perfTestService.getLogFile(id, path);
    FileDownloadUtils.downloadFile(response, targetFile);
  }

  /**
   * Show the given log for the perf test having the given id.
   *
   * @param user     user
   * @param id       test id
   * @param path     path in the log folder
   * @param response response
   */
  @RequestMapping(value = "/{id}/show_log/**")
  public void showLog(User user, @PathVariable("id") long id, @RemainedPath String path, HttpServletResponse response) {
    getOneWithPermissionCheck(user, id, false);
    File targetFile = perfTestService.getLogFile(id, path);
    response.reset();
    response.setContentType("text/plain");
    response.setCharacterEncoding("UTF-8");
    FileInputStream fileInputStream = null;
    try {
      fileInputStream = new FileInputStream(targetFile);
      ServletOutputStream outputStream = response.getOutputStream();
      if (FilenameUtils.isExtension(targetFile.getName(), "zip")) {
        // Limit log view to 1MB
        outputStream.println(" Only the last 1MB of a log shows.\n");
        outputStream.println("==========================================================================\n\n");
        LogCompressUtils.decompress(fileInputStream, outputStream, 1 * 1024 * 1204);
      } else {
        IOUtils.copy(fileInputStream, outputStream);
      }
    } catch (Exception e) {
      CoreLogger.LOGGER.error("Error while processing log. {}", targetFile, e);
    } finally {
      IOUtils.closeQuietly(fileInputStream);
    }
  }

  /**
   * Get the running perf test info having the given id.
   *
   * @param user user
   * @param id   test id
   * @return JSON message  containing test,agent and monitor status.
   */
  @RequestMapping(value = "/{id}/api/sample")
  @RestAPI
  public HttpEntity<String> refreshTestRunning(User user, @PathVariable("id") long id) {
    PerfTest test = checkNotNull(getOneWithPermissionCheck(user, id, false), "given test should be exist : " + id);
    Map<String, Object> map = newHashMap();
    map.put("status", test.getStatus());
    map.put("perf", perfTestService.getStatistics(test));
    map.put("agent", perfTestService.getAgentStat(test));
    map.put("monitor", perfTestService.getMonitorStat(test));
    return toJsonHttpEntity(map);
  }

  /**
   * Get the detailed perf test report.
   *
   * @param model model
   * @param id    test id
   * @return perftest/detail_report
   */
  @SuppressWarnings("MVCPathVariableInspection")
  @RequestMapping(value = {"/{id}/detail_report", /** for backward compatibility */"/{id}/report"})
  public String getReport(ModelMap model, @PathVariable("id") long id) {
    model.addAttribute("test", perfTestService.getOne(id));
    model.addAttribute("plugins", perfTestService.getAvailableReportPlugins(id));
    return "perftest/detail_report";
  }

  /**
   * Get the detailed perf test report.
   *
   * @param id test id
   * @return perftest/detail_report/perf
   */
  @SuppressWarnings({"MVCPathVariableInspection", "UnusedParameters"})
  @RequestMapping("/{id}/detail_report/perf")
  public String getDetailPerfReport(@PathVariable("id") long id) {
    return "perftest/detail_report/perf";
  }

  /**
   * Get the detailed perf test monitor report.
   *
   * @param id       test id
   * @param targetIP target ip
   * @param modelMap model map
   * @return perftest/detail_report/monitor
   */
  @SuppressWarnings("UnusedParameters")
  @RequestMapping("/{id}/detail_report/monitor")
  public String getDetailMonitorReport(@PathVariable("id") long id, @RequestParam("targetIP") String targetIP,
                                       ModelMap modelMap) {
    modelMap.addAttribute("targetIP", targetIP);
    return "perftest/detail_report/monitor";
  }

  /**
   * Get the detailed perf test report.
   *
   * @param id       test id
   * @param plugin   test report plugin category
   * @param modelMap model map
   * @return perftest/detail_report/plugin
   */
  @SuppressWarnings("UnusedParameters")
  @RequestMapping("/{id}/detail_report/plugin/{plugin}")
  public String getDetailPluginReport(@PathVariable("id") long id,
                                      @PathVariable("plugin") String plugin, @RequestParam("kind") String kind, ModelMap modelMap) {
    modelMap.addAttribute("plugin", plugin);
    modelMap.addAttribute("kind", kind);
    return "perftest/detail_report/plugin";
  }


  private PerfTest getOneWithPermissionCheck(User user, Long id, boolean withTag) {
    PerfTest perfTest = withTag ? perfTestService.getOneWithTag(id) : perfTestService.getOne(id);
    if (user.getRole().equals(Role.ADMIN) || user.getRole().equals(Role.SUPER_USER)) {
      return perfTest;
    }
    if (perfTest != null && !user.equals(perfTest.getCreatedUser())) {
      throw processException("User " + user.getUserId() + " has no right on PerfTest " + id);
    }
    return perfTest;
  }


  private Map<String, String> getMonitorGraphData(long id, String targetIP, int imgWidth) {
    int interval = perfTestService.getMonitorGraphInterval(id, targetIP, imgWidth);
    Map<String, String> sysMonitorMap = perfTestService.getMonitorGraph(id, targetIP, interval);
    PerfTest perfTest = perfTestService.getOne(id);
    sysMonitorMap.put("interval", String.valueOf(interval * (perfTest != null ? perfTest.getSamplingInterval() : 1)));
    return sysMonitorMap;
  }


  /**
   * Get the count of currently running perf test and the detailed progress info for the given perf test IDs.
   *
   * @param user user
   * @param ids  comma separated perf test list
   * @return JSON message containing perf test status
   */
  @RestAPI
  @RequestMapping("/api/status")
  public HttpEntity<String> getStatuses(User user, @RequestParam(value = "ids", defaultValue = "") String ids) {
    List<PerfTest> perfTests = perfTestService.getAll(user, convertString2Long(ids));
    return toJsonHttpEntity(buildMap("perfTestInfo", perfTestService.getCurrentPerfTestStatistics(), "status",
        getStatus(perfTests)));
  }

  /**
   * Get all available scripts in JSON format for the current factual user.
   *
   * @param user    user
   * @param ownerId owner id
   * @return JSON containing script's list.
   */
  @RestAPI
  @RequestMapping("/api/script")
  public HttpEntity<String> getScripts(User user, @RequestParam(value = "ownerId", required = false) String ownerId) {
    if (StringUtils.isNotEmpty(ownerId)) {
      user = userService.getOne(ownerId);
    }
    List<FileEntry> scripts = newArrayList(filter(fileEntryService.getAll(user),
        new com.google.common.base.Predicate<FileEntry>() {
          @Override
          public boolean apply(@Nullable FileEntry input) {
            return input != null && input.getFileType().getFileCategory() == FileCategory.SCRIPT;
          }
        }));
    return toJsonHttpEntity(scripts, fileEntryGson);
  }


  /**
   * Get resources and lib file list from the same folder with the given script path.
   *
   * @param user       user
   * @param scriptPath script path
   * @param ownerId    ownerId
   * @return json string representing resources and libs.
   */
  @RequestMapping("/api/resource")
  public HttpEntity<String> getResources(User user, @RequestParam String scriptPath,
                                         @RequestParam(required = false) String ownerId) {
    if (user.getRole() == Role.ADMIN && StringUtils.isNotBlank(ownerId)) {
      user = userService.getOne(ownerId);
    }
    FileEntry fileEntry = fileEntryService.getOne(user, scriptPath);
    String targetHosts = "";
    List<String> fileStringList = newArrayList();
    if (fileEntry != null) {
      List<FileEntry> fileList = fileEntryService.getScriptHandler(fileEntry).getLibAndResourceEntries(user, fileEntry, -1L);
      for (FileEntry each : fileList) {
        fileStringList.add(each.getPath());
      }
      targetHosts = filterHostString(fileEntry.getProperties().get("targetHosts"));
    }

    return toJsonHttpEntity(buildMap("targetHosts", trimToEmpty(targetHosts), "resources", fileStringList));
  }


  /**
   * Get the status of the given perf test.
   *
   * @param user user
   * @param id   perftest id
   * @return JSON message containing perf test status
   */
  @RestAPI
  @RequestMapping("/api/{id}/status")
  public HttpEntity<String> getStatus(User user, @PathVariable("id") Long id) {
    List<PerfTest> perfTests = perfTestService.getAll(user, new Long[]{id});
    return toJsonHttpEntity(buildMap("status", getStatus(perfTests)));
  }

  /**
   * Get the logs of the given perf test.
   *
   * @param user user
   * @param id   perftest id
   * @return JSON message containing log file names
   */
  @RestAPI
  @RequestMapping("/api/{id}/logs")
  public HttpEntity<String> getLogs(User user, @PathVariable("id") Long id) {
    // Check permission
    getOneWithPermissionCheck(user, id, false);
    return toJsonHttpEntity(perfTestService.getLogFiles(id));
  }

  /**
   * Get the detailed report graph data for the given perf test id.
   * This method returns the appropriate points based on the given imgWidth.
   *
   * @param id       test id
   * @param dataType which data
   * @param imgWidth imageWidth
   * @return json string.
   */
  @SuppressWarnings("MVCPathVariableInspection")
  @RestAPI
  @RequestMapping({"/api/{id}/perf", "/api/{id}/graph"})
  public HttpEntity<String> getPerfGraph(@PathVariable("id") long id,
                                         @RequestParam(required = true, defaultValue = "") String dataType,
                                         @RequestParam(defaultValue = "false") boolean onlyTotal,
                                         @RequestParam int imgWidth) {
    String[] dataTypes = checkNotEmpty(StringUtils.split(dataType, ","), "dataType argument should be provided");
    return toJsonHttpEntity(getPerfGraphData(id, dataTypes, onlyTotal, imgWidth));
  }


  /**
   * Get the monitor data of the target having the given IP.
   *
   * @param id       test Id
   * @param targetIP targetIP
   * @param imgWidth image width
   * @return json message
   */
  @RestAPI
  @RequestMapping("/api/{id}/monitor")
  public HttpEntity<String> getMonitorGraph(@PathVariable("id") long id,
                                            @RequestParam("targetIP") String targetIP, @RequestParam int imgWidth) {
    return toJsonHttpEntity(getMonitorGraphData(id, targetIP, imgWidth));
  }

  /**
   * Get the plugin monitor data of the target.
   *
   * @param id       test Id
   * @param plugin   monitor plugin category
   * @param kind     kind
   * @param imgWidth image width
   * @return json message
   */
  @RestAPI
  @RequestMapping("/api/{id}/plugin/{plugin}")
  public HttpEntity<String> getPluginGraph(@PathVariable("id") long id,
                                           @PathVariable("plugin") String plugin,
                                           @RequestParam("kind") String kind, @RequestParam int imgWidth) {
    return toJsonHttpEntity(getReportPluginGraphData(id, plugin, kind, imgWidth));
  }

  private Map<String, Object> getReportPluginGraphData(long id, String plugin, String kind, int imgWidth) {
    int interval = perfTestService.getReportPluginGraphInterval(id, plugin, kind, imgWidth);
    Map<String, Object> pluginMonitorData = perfTestService.getReportPluginGraph(id, plugin, kind, interval);
    final PerfTest perfTest = perfTestService.getOne(id);
    int samplingInterval = 3;
    if (perfTest != null) {
      samplingInterval = perfTest.getSamplingInterval();
    }
    pluginMonitorData.put("interval", interval * samplingInterval);
    return pluginMonitorData;
  }


  /**
   * Get the last perf test details in the form of json.
   *
   * @param user user
   * @param page page
   * @param size size of retrieved perf test
   * @return json string
   */
  @RestAPI
  @RequestMapping(value = {"/api/last", "/api", "/api/"}, method = RequestMethod.GET)
  public HttpEntity<String> getAll(User user, @RequestParam(value = "page", defaultValue = "0") int page,
                                   @RequestParam(value = "size", defaultValue = "1") int size) {
    PageRequest pageRequest = new PageRequest(page, size, new Sort(Direction.DESC, "id"));
    Page<PerfTest> testList = perfTestService.getPagedAll(user, null, null, null, pageRequest);
    return toJsonHttpEntity(testList.getContent());
  }

  /**
   * Get the perf test detail in the form of json.
   *
   * @param user user
   * @param id   perftest id
   * @return json message containing test info.
   */
  @RestAPI
  @RequestMapping(value = "/api/{id}", method = RequestMethod.GET)
  public HttpEntity<String> getOne(User user, @PathVariable("id") Long id) {
    PerfTest test = checkNotNull(getOneWithPermissionCheck(user, id, false), "PerfTest %s does not exists", id);
    return toJsonHttpEntity(test);
  }

  /**
   * Create the given perf test.
   *
   * @param user     user
   * @param perfTest perf test
   * @return json message containing test info.
   */
  @RestAPI
  @RequestMapping(value = {"/api/", "/api"}, method = RequestMethod.POST)
  public HttpEntity<String> create(User user, PerfTest perfTest) {
    checkNull(perfTest.getId(), "id should be null");
    validate(user, null, perfTest);
    PerfTest savePerfTest = perfTestService.save(user, perfTest);
    return toJsonHttpEntity(savePerfTest);
  }

  /**
   * Delete the given perf test.
   *
   * @param user user
   * @param id   perf test id
   * @return json success message if succeeded
   */
  @RestAPI
  @RequestMapping(value = "/api/{id}", method = RequestMethod.DELETE)
  public HttpEntity<String> delete(User user, @PathVariable("id") Long id) {
    PerfTest perfTest = getOneWithPermissionCheck(user, id, false);
    checkNotNull(perfTest, "no perftest for %s exits", id);
    perfTestService.delete(user, id);
    return successJsonHttpEntity();
  }


  /**
   * Update the given perf test.
   *
   * @param user     user
   * @param id       perf test id
   * @param perfTest perf test configuration changes
   * @return json message
   */
  @RestAPI
  @RequestMapping(value = "/api/{id}", method = RequestMethod.PUT)
  public HttpEntity<String> update(User user, @PathVariable("id") Long id, PerfTest perfTest) {
    PerfTest existingPerfTest = getOneWithPermissionCheck(user, id, false);
    perfTest.setId(id);
    validate(user, existingPerfTest, perfTest);
    return toJsonHttpEntity(perfTestService.save(user, perfTest));
  }

  /**
   * Stop the given perf test.
   *
   * @param user user
   * @param id   perf test id
   * @return json success message if succeeded
   */
  @RestAPI
  @RequestMapping(value = "/api/{id}", params = "action=stop", method = RequestMethod.PUT)
  public HttpEntity<String> stop(User user, @PathVariable("id") Long id) {
    perfTestService.stop(user, id);
    return successJsonHttpEntity();
  }


  /**
   * Update the given perf test's status.
   *
   * @param user   user
   * @param id     perf test id
   * @param status Status to be moved to
   * @return json message
   */
  @RestAPI
  @RequestMapping(value = "/api/{id}", params = "action=status", method = RequestMethod.PUT)
  public HttpEntity<String> updateStatus(User user, @PathVariable("id") Long id, Status status) {
    PerfTest perfTest = getOneWithPermissionCheck(user, id, false);
    checkNotNull(perfTest, "no perftest for %s exits", id).setStatus(status);
    validate(user, null, perfTest);
    return toJsonHttpEntity(perfTestService.save(user, perfTest));
  }

  /**
   * Clone and start the given perf test.
   *
   * @param user     user
   * @param id       perf test id to be cloned
   * @param perftest option to override while cloning.
   * @return json string
   */
  @SuppressWarnings("MVCPathVariableInspection")
  @RestAPI
  @RequestMapping(value = {"/api/{id}/clone_and_start", /* for backward compatibility */ "/api/{id}/cloneAndStart"})
  public HttpEntity<String> cloneAndStart(User user, @PathVariable("id") Long id, PerfTest perftest) {
    PerfTest test = getOneWithPermissionCheck(user, id, false);
    checkNotNull(test, "no perftest for %s exits", id);
    PerfTest newOne = test.cloneTo(new PerfTest());
    newOne.setStatus(Status.READY);
    if (perftest != null) {
      if (perftest.getScheduledTime() != null) {
        newOne.setScheduledTime(perftest.getScheduledTime());
      }
      if (perftest.getScriptRevision() != null) {
        newOne.setScriptRevision(perftest.getScriptRevision());
      }

      if (perftest.getAgentCount() != null) {
        newOne.setAgentCount(perftest.getAgentCount());
      }
    }
    if (newOne.getAgentCount() == null) {
      newOne.setAgentCount(0);
    }
    Map<String, MutableInt> agentCountMap = agentManagerService.getAvailableAgentCountMap(user);
    MutableInt agentCountObj = agentCountMap.get(isClustered() ? test.getRegion() : Config.NONE_REGION);
    checkNotNull(agentCountObj, "test region should be within current region list");
    int agentMaxCount = agentCountObj.intValue();
    checkArgument(newOne.getAgentCount() != 0, "test agent should not be %s", agentMaxCount);
    checkArgument(newOne.getAgentCount() <= agentMaxCount, "test agent should be equal to or less than %s",
        agentMaxCount);
    PerfTest savePerfTest = perfTestService.save(user, newOne);
    CoreLogger.LOGGER.info("test {} is created through web api by {}", savePerfTest.getId(), user.getUserId());
    return toJsonHttpEntity(savePerfTest);
  }
}
TOP

Related Classes of org.ngrinder.perftest.controller.PerfTestController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.