package com.intuit.tank.harness; /* * #%L * Intuit Tank Agent (apiharness) * %% * Copyright (C) 2011 - 2015 Intuit Inc. * %% * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * #L% */ import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.text.DateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.CountDownLatch; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; import com.intuit.tank.AgentServiceClient; import com.intuit.tank.api.model.v1.cloud.CloudVmStatus; import com.intuit.tank.api.model.v1.cloud.VMStatus; import com.intuit.tank.api.model.v1.cloud.ValidationStatus; import com.intuit.tank.harness.data.HDTestPlan; import com.intuit.tank.harness.data.HDWorkload; import com.intuit.tank.harness.logging.LogUtil; import com.intuit.tank.logging.LogEventType; import com.intuit.tank.logging.LoggingProfile; import com.intuit.tank.reporting.api.DummyResultsReporter; import com.intuit.tank.reporting.api.ResultsReporter; import com.intuit.tank.reporting.factory.ReportingFactory; import com.intuit.tank.results.TankResult; import com.intuit.tank.runner.TestPlanRunner; import com.intuit.tank.vm.agent.messages.AgentData; import com.intuit.tank.vm.agent.messages.AgentTestStartData; import com.intuit.tank.vm.agent.messages.DataFileRequest; import com.intuit.tank.vm.agent.messages.WatsAgentStatusResponse; import com.intuit.tank.vm.api.enumerated.JobStatus; import com.intuit.tank.vm.api.enumerated.VMImageType; import com.intuit.tank.vm.api.enumerated.VMRegion; import com.intuit.tank.vm.api.enumerated.WatsAgentCommand; import com.intuit.tank.vm.common.TankConstants; import com.intuit.tank.vm.settings.TankConfig; public class APITestHarness { private static Logger LOG = LogManager.getLogger(APITestHarness.class); public static final int POLL_INTERVAL = 15000; private static final int RETRY_SLEEP = 2000; private static final int MAX_RETRIES = 10; private static APITestHarness instance; private AgentRunData agentRunData; private static final int BATCH_SIZE = 100; private String testPlans = ""; private String instanceId; private List<String> testPlanXmls = null; private ThreadGroup threadGroup = new ThreadGroup("Test Runner Group"); private int currentNumThreads = 0; private long startTime = 0; private int capacity = -1; private boolean DEBUG = false; private boolean logTiming = true; private boolean isLocal = true; private boolean started = false; private WatsAgentCommand cmd = WatsAgentCommand.run; private Thread[] sessionThreads; private CountDownLatch doneSignal; private boolean loggedSimTime; private int currentUsers = 0; private Vector<TankResult> results = new Vector<TankResult>(); private ValidationStatus validationFailures; private TankConfig tankConfig; private UserTracker userTracker = new UserTracker(); private FlowController flowControllerTemplate; private Map<Long, FlowController> controllerMap = new HashMap<Long, FlowController>(); private TPSMonitor tpsMonitor; private ResultsReporter resultsReporter; private String tankHttpClientClass; private Calendar c = Calendar.getInstance(); private Date send = new Date(); private int interval = 15; // SECONDS static { try { java.security.Security.setProperty("networkaddress.cache.ttl", "0"); } catch (Throwable e1) { LOG.warn(LogUtil.getLogMessage("Error setting dns timeout: " + e1.toString(), LogEventType.System)); } try { System.setProperty("jsse.enableSNIExtension", "false"); } catch (Throwable e1) { LOG.warn(LogUtil.getLogMessage("Error disabling SNI extension: " + e1.toString(), LogEventType.System)); } try { System.setProperty("jdk.certpath.disabledAlgorithms", ""); } catch (Throwable e1) { System.err.println("Error setting property jdk.certpath.disabledAlgorithms: " + e1.toString()); e1.printStackTrace(); } } /** * * @return */ public static APITestHarness getInstance() { if (instance == null) { instance = new APITestHarness(); } return instance; } public static void destroyCurrentInstance() { instance = null; } private APITestHarness() { tankConfig = new TankConfig(); validationFailures = new ValidationStatus(); setFlowControllerTemplate(new DefaultFlowController()); agentRunData = new AgentRunData(); } /** * @param args */ public static void main(String[] args) { // set ttl on dns to small value try { java.security.Security.setProperty("networkaddress.cache.ttl", "0"); } catch (Throwable e1) { LOG.warn(LogUtil.getLogMessage("Error setting dns timeout: " + e1.toString(), LogEventType.System)); } try { System.setProperty("jsse.enableSNIExtension", "false"); } catch (Throwable e1) { LOG.warn(LogUtil.getLogMessage("Error disabling SNI extension: " + e1.toString(), LogEventType.System)); } if (args.length < 1) { usage(); return; } getInstance().initializeFromArgs(args); } private void initializeFromArgs(String[] args) { String controllerBase = null; for (int iter = 0; iter < args.length; ++iter) { String argument = args[iter]; LOG.info("checking arg " + argument); String[] values = argument.split("="); if (values[0].equalsIgnoreCase("-tp")) { testPlans = values[1]; if (!AgentUtil.validateTestPlans(testPlans)) { return; } continue; } else if (values[0].equalsIgnoreCase("-ramp")) { agentRunData.setRampTime(Long.parseLong(values[1]) * 60000); continue; } else if (values[0].equalsIgnoreCase("-client")) { tankHttpClientClass = StringUtils.trim(values[1]); continue; } else if (values[0].equalsIgnoreCase("-d")) { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); LoggerConfig loggerConfig = new LoggerConfig(); loggerConfig.setLevel(Level.DEBUG); config.addLogger("com.intuit.tank.http", loggerConfig); config.addLogger("com.intuit.tank", loggerConfig); ctx.updateLoggers(config); DEBUG = true; agentRunData.setActiveProfile(LoggingProfile.VERBOSE); setFlowControllerTemplate(new DebugFlowController()); continue; } else if (values[0].equalsIgnoreCase("-local")) { isLocal = true; continue; } else if (values[0].equalsIgnoreCase("-instanceId")) { instanceId = values[1]; continue; } else if (values[0].equalsIgnoreCase("-logging")) { agentRunData.setActiveProfile(LoggingProfile.fromString(values[1])); continue; } else if (values[0].equalsIgnoreCase("-users")) { agentRunData.setNumUsers(Integer.parseInt(values[1])); continue; } else if (values[0].equalsIgnoreCase("-capacity")) { capacity = Integer.parseInt(values[1]); continue; } else if (values[0].equalsIgnoreCase("-start")) { agentRunData.setNumStartUsers(Integer.parseInt(values[1])); continue; } else if (values[0].equalsIgnoreCase("-jobId")) { agentRunData.setJobId(values[1]); continue; } else if (values[0].equalsIgnoreCase("-stopBehavior")) { agentRunData.setStopBehavior(StopBehavior.fromString(values[1])); continue; } else if (values[0].equalsIgnoreCase("-http")) { controllerBase = (values.length > 1 ? values[1] : null); continue; } else if (values[0].equalsIgnoreCase("-time")) { agentRunData.setSimulationTime(Integer.parseInt(values[1]) * 60000); continue; } } if (instanceId == null) { try { instanceId = AmazonUtil.getInstanceId(); if (instanceId == null) { instanceId = getLocalInstanceId(); } } catch (Exception e) { instanceId = getLocalInstanceId(); } } if (agentRunData.getActiveProfile() == null && !isLocal) { agentRunData.setActiveProfile(AmazonUtil.getLoggingProfile()); } agentRunData.setMachineName(instanceId); agentRunData.setInstanceId(instanceId); if (controllerBase != null) { resultsReporter = ReportingFactory.getResultsReporter(); startHttp(controllerBase); } else { resultsReporter = new DummyResultsReporter(); TestPlanSingleton plans = TestPlanSingleton.getInstance(); if (null == testPlanXmls) { plans.setTestPlans(testPlans); } else { plans.setTestPlans(testPlanXmls); } runConcurrentTestPlans(); } } private String getLocalInstanceId() { isLocal = true; String iId = "local-instance"; try { iId = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e1) { // cannot determine instanceid } return iId; } /** * Display usage error text */ private static void usage() { System.out.println("API Test Harness Usage:"); System.out.println("java -jar apiharness-1.0-all.jar -tp=<test plan file>"); System.out.println("-tp=<file name>: The test plan file to execute"); System.out.println("-ramp=<time>: The time (min) to get to the ideal concurrent users specified"); System.out.println("-time=<time>: The time (min) of the simulation"); System.out.println("-users=<# of total users>: The number of total users to run concurrently"); System.out .println("-start=<# of users to start with>: The number of users to run concurrently when test begins"); System.out.println("-http=<controller_base_url>: The url of the controller to get test info from"); System.out.println("-d: Turns debug on to step through each request"); } private void startHttp(String baseUrl) { isLocal = false; CommandListener.startHttpServer(tankConfig.getAgentConfig().getAgentPort()); if (baseUrl == null) { baseUrl = AmazonUtil.getControllerBaseUrl(); } AgentServiceClient client = new AgentServiceClient(baseUrl); String instanceUrl = null; int tries = 0; while (instanceUrl == null) { try { instanceUrl = "http://" + AmazonUtil.getPublicHostName() + ":" + tankConfig.getAgentConfig().getAgentPort(); LOG.info("MyInstanceURL = " + instanceUrl); } catch (IOException e1) { tries++; if (tries < 10) { try { Thread.sleep(200); } catch (InterruptedException e) { // ignore } } else { LOG.error("Error getting amazon host. maybe local."); String publicIp = new HostInfo().getPublicIp(); if (!publicIp.equals(HostInfo.UNKNOWN)) { instanceUrl = "http://" + publicIp + ":" + tankConfig.getAgentConfig().getAgentPort(); LOG.info("MyInstanceURL from hostinfo = " + instanceUrl); } else { instanceUrl = "http://localhost:" + tankConfig.getAgentConfig().getAgentPort(); } } } } LOG.info("MyInstanceURL = " + instanceUrl); if (capacity < 0) { capacity = AmazonUtil.getCapacity(); } VMRegion region = VMRegion.STANDALONE; if (AmazonUtil.isInAmazon()) { try { region = AmazonUtil.getVMRegion(); } catch (IOException e) { LOG.warn(LogUtil.getLogMessage("Error getting region. using CUSTOM...", LogEventType.System)); } } if (agentRunData.getJobId() == null) { agentRunData.setJobId(AmazonUtil.getJobId()); agentRunData.setStopBehavior(AmazonUtil.getStopBehavior()); } LogUtil.getLogEvent().setJobId(agentRunData.getJobId()); LOG.info(LogUtil.getLogMessage("Active Profile" + agentRunData.getActiveProfile().getDisplayName())); AgentData data = new AgentData(agentRunData.getJobId(), instanceId, instanceUrl, capacity, region, AmazonUtil.getZone()); try { AgentTestStartData startData = null; int count = 0; LOG.info(LogUtil.getLogMessage("Sending AgentData to controller: " + data.toString(), LogEventType.System)); while (count < 10) { try { startData = client.agentReady(data); break; } catch (Exception e) { LOG.error("Error sending ready: " + e, e); count++; } } writeXmlToFile(startData.getScriptUrl()); agentRunData.setNumUsers(startData.getConcurrentUsers()); agentRunData.setNumStartUsers(startData.getStartUsers()); agentRunData.setRampTime(startData.getRampTime()); agentRunData.setJobId(startData.getJobId()); agentRunData.setUserInterval(startData.getUserIntervalIncrement()); agentRunData.setSimulationTime(startData.getSimulationTime()); agentRunData.setAgentInstanceNum(startData.getAgentInstanceNum()); agentRunData.setTotalAgents(startData.getTotalAgents()); if (startData.getDataFiles() != null) { for (DataFileRequest dfRequest : startData.getDataFiles()) { saveDataFile(dfRequest); } } Thread t = new Thread(new StartedChecker()); t.setName("StartedChecker"); t.setDaemon(false); t.start(); } catch (Exception e) { LOG.error("Error communicating with controller: " + e, e); System.exit(0); } } /** * @throws IOException * */ public void writeXmlToFile(String scriptUrl) throws IOException { File f = new File("script.xml"); LOG.info(LogUtil.getLogMessage("Writing xml to " + f.getAbsolutePath())); Writer out = null; InputStream is = null; int count = 0; while (count++ < MAX_RETRIES) { try { if (f.exists()) { f.delete(); f = new File("script.xml"); } URL url = new URL(scriptUrl); LOG.info("Downloading file from url " + scriptUrl + " to file " + f.getAbsolutePath()); is = url.openStream(); out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(f), "UTF8")); IOUtils.copy(is, out); IOUtils.closeQuietly(is); IOUtils.closeQuietly(out); String scriptXML = FileUtils.readFileToString(f, "UTF-8"); List<String> tps = new ArrayList<String>(); tps.add(scriptXML); setTestPlans(tps); TestPlanSingleton.getInstance().setTestPlans(tps); break; } catch (Exception e) { if (count < MAX_RETRIES) { IOUtils.closeQuietly(is); IOUtils.closeQuietly(out); LOG.warn(LogUtil.getLogMessage("Failed to download script file because of: " + e.toString() + ". Will try " + (MAX_RETRIES - count) + " more times.", LogEventType.System)); try { Thread.sleep(RETRY_SLEEP); } catch (InterruptedException e1) { // ignore } } else { LOG.error(LogUtil.getLogMessage("Error writing script file: " + e, LogEventType.IO), e); throw new RuntimeException(e); } } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(out); } } } private void saveDataFile(DataFileRequest dataFileRequest) { String dataFileDirPath = new TankConfig().getAgentConfig().getAgentDataFileStorageDir(); File dataFileDir = new File(dataFileDirPath); if (!dataFileDir.exists()) { if (!dataFileDir.mkdirs()) { throw new RuntimeException("Cannot create data file dir " + dataFileDirPath); } } File dataFile = new File(dataFileDir, dataFileRequest.getFileName()); FileOutputStream fos = null; InputStream is = null; int count = 0; while (count++ < MAX_RETRIES) { try { URL url = new URL(dataFileRequest.getFileUrl()); LOG.info(LogUtil.getLogMessage( "writing file " + dataFileRequest.getFileName() + " to " + dataFile.getAbsolutePath() + " from url " + url.toExternalForm(), LogEventType.System)); is = url.openStream(); fos = new FileOutputStream(dataFile); IOUtils.copy(is, fos); IOUtils.closeQuietly(fos); if (dataFileRequest.isDefault() && !dataFileRequest.getFileName().equals(TankConstants.DEFAULT_CSV_FILE_NAME)) { File defaultFile = new File(dataFileDir, TankConstants.DEFAULT_CSV_FILE_NAME); LOG.debug("Copying default file " + dataFile.getAbsolutePath() + " to " + defaultFile.getAbsolutePath()); FileUtils.copyFile(dataFile, defaultFile); } break; } catch (Exception e) { if (count < MAX_RETRIES) { LOG.warn(LogUtil.getLogMessage("Failed to download CSV file because of: " + e.toString() + ". Will try " + (MAX_RETRIES - count) + " more times.", LogEventType.System)); try { Thread.sleep(RETRY_SLEEP); } catch (InterruptedException e1) { // ignore } } else { LOG.error(LogUtil.getLogMessage("Error downloading csv file: " + e, LogEventType.IO), e); throw new RuntimeException(e); } } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(fos); } } } /** * */ public synchronized void addKill() { validationFailures.addKill(); } /** * */ public synchronized void addAbort() { validationFailures.addAbort(); } /** * */ public synchronized void addGoto() { validationFailures.addGoto(); } /** * */ public synchronized void addSkip() { validationFailures.addSkip(); } /** * */ public synchronized void addSkipGroup() { validationFailures.addSkipGroup(); } /** * */ public synchronized void addRestart() { validationFailures.addRestart(); } public UserTracker getUserTracker() { return userTracker; } /** * Run concurrent test plans at the same time * * @param parser */ public void runConcurrentTestPlans() { if (started) { LOG.warn("Agent already started. Ignoring start command"); return; } tpsMonitor = new TPSMonitor(tankConfig.getAgentConfig().getTPSPeriod()); StringBuilder info = new StringBuilder().append(" RAMP_TIME=").append(agentRunData.getRampTime()) .append("; agentRunData.getNumUsers()=").append(agentRunData.getNumUsers()) .append("; NUM_START_THREADS=").append(agentRunData.getNumStartUsers()) .append("; simulationTime=").append(agentRunData.getSimulationTime()); LOG.info(LogUtil.getLogMessage("starting test with " + info.toString())); started = true; if (agentRunData.getJobId() == null) { String jobId = AmazonUtil.getJobId(); agentRunData.setJobId(jobId); } TestPlanRunner[] sessions = new TestPlanRunner[agentRunData.getNumUsers()]; sessionThreads = new Thread[agentRunData.getNumUsers()]; Thread monitorThread = null; doneSignal = new CountDownLatch(agentRunData.getNumUsers()); try { HDWorkload hdWorkload = TestPlanSingleton.getInstance().getTestPlans().get(0); if (StringUtils.isBlank(tankHttpClientClass)) { tankHttpClientClass = hdWorkload.getTankHttpClientClass(); } agentRunData.setProjectName(hdWorkload.getName()); agentRunData.setTankhttpClientClass(tankHttpClientClass); List<TestPlanStarter> testPlans = new ArrayList<TestPlanStarter>(); int total = 0; for (HDTestPlan plan : hdWorkload.getPlans()) { if (plan.getUserPercentage() > 0) { plan.setVariables(hdWorkload.getVariables()); TestPlanStarter starter = new TestPlanStarter(plan, agentRunData.getNumUsers()); total += starter.getNumThreads(); testPlans.add(starter); LOG.info(LogUtil.getLogMessage("Users for Test Plan " + plan.getTestPlanName() + " at " + plan.getUserPercentage() + "% = " + starter.getNumThreads())); } } LOG.info(LogUtil.getLogMessage("Total Users calculated for all test Plans = " + total)); if (total != agentRunData.getNumUsers()) { int numToAdd = agentRunData.getNumUsers() - total; TestPlanStarter starter = testPlans.get(testPlans.size() - 1); LOG.info(LogUtil.getLogMessage("adding " + numToAdd + " threads to testPlan " + starter.getPlan().getTestPlanName())); starter.setNumThreads(starter.getNumThreads() + numToAdd); } // create threads int tp = 0; for (TestPlanStarter starter : testPlans) { for (int i = 0; i < starter.getNumThreads(); i++) { sessions[tp] = new TestPlanRunner(starter.getPlan(), tp); sessionThreads[tp] = new Thread(threadGroup, sessions[tp], "AGENT"); sessionThreads[tp].setDaemon(true);// system won't shut down normally until all user threads stop starter.addThread(sessionThreads[tp]); sessions[tp].setUniqueName( sessionThreads[tp].getThreadGroup().getName() + "-" + sessionThreads[tp].getId()); tp++; } } LOG.info(LogUtil.getLogMessage("Have all testPlan runners configured")); // start status thread first only if (!isLocal && !isDebug() && NumberUtils.isDigits(agentRunData.getJobId())) { LOG.info(LogUtil.getLogMessage("Starting monitor thread...")); CloudVmStatus status = getInitialStatus(); monitorThread = new Thread(new APIMonitor(status)); monitorThread.setDaemon(true); monitorThread.setPriority(Thread.NORM_PRIORITY - 2); monitorThread.start(); } LOG.info(LogUtil.getLogMessage("Starting threads...")); // start initial users startTime = System.currentTimeMillis(); DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM); LOG.info(LogUtil.getLogMessage("Simulation start: " + df.format(new Date(getStartTime())))); if (agentRunData.getSimulationTime() != 0) { LOG.info(LogUtil.getLogMessage("Scheduled Simulation End : " + df.format(new Date(getSimulationEndTimeMillis())))); LOG.info(LogUtil.getLogMessage("Max Simulation End : " + df.format(new Date(getMaxSimulationEndTimeMillis())))); } else { LOG.info(LogUtil.getLogMessage("Ends at script loops completed with no Max Simulation Time.")); } currentNumThreads = 0; if (agentRunData.getNumUsers() > 0) { for (TestPlanStarter starter : testPlans) { if (isDebug()) { starter.run(); } else { Thread t = new Thread(starter); t.setDaemon(true); t.start(); } } boolean ramping = true; while (ramping) { boolean done = true; for (TestPlanStarter starter : testPlans) { done = done && starter.isDone(); } ramping = !done; if (ramping) { Thread.sleep(5000); } } // if we broke early, fix our countdown latch int numToCount = 0; for (TestPlanStarter starter : testPlans) { numToCount += starter.getThreadsStarted(); } while (numToCount < agentRunData.getNumUsers()) { doneSignal.countDown(); numToCount++; } // wait for them to finish LOG.info(LogUtil.getLogMessage("Ramp Complete...")); doneSignal.await(); } } catch (Throwable t) { LOG.error("error executing..." + t, t); } finally { LOG.info(LogUtil.getLogMessage("Test Complete...")); if (!isDebug() && NumberUtils.isDigits(agentRunData.getJobId())) { if (null != monitorThread) { APIMonitor.setJobStatus(JobStatus.Completed); APIMonitor.setDoMonitor(false); } sendBatchToDB(false); // sleep for 60 seconds to let wily agent clear any data try { Thread.sleep(60000); } catch (InterruptedException e) { // nothing to do } } } flowControllerTemplate.endTest(); // System.exit(0); } public TPSMonitor getTPMonitor() { return tpsMonitor; } /** * @return * @throws IOException */ public CloudVmStatus getInitialStatus() { CloudVmStatus status = null; try { VMRegion region = VMRegion.STANDALONE; String secGroups = "unknown"; if (AmazonUtil.isInAmazon()) { try { region = AmazonUtil.getVMRegion(); secGroups = AmazonUtil.getMetaData(CloudMetaDataType.security_groups); } catch (IOException e) { LOG.warn(LogUtil.getLogMessage("Error gettting region. using Custom...", LogEventType.System)); } } status = new CloudVmStatus(instanceId, agentRunData.getJobId(), secGroups, JobStatus.Unknown, VMImageType.AGENT, region, VMStatus.running, new ValidationStatus(), 0, 0, new Date(), null); } catch (Exception e) { LOG.error(LogUtil.getLogMessage("Error creating intial status.")); status = new CloudVmStatus(instanceId, "unknown", "wats-dev", JobStatus.Unknown, VMImageType.AGENT, VMRegion.US_EAST, VMStatus.running, new ValidationStatus(), 0, 0, new Date(), null); } status.setUserDetails(userTracker.getSnapshot()); return status; } synchronized public void threadComplete() { currentUsers--; doneSignal.countDown(); long count = doneSignal.getCount(); // numCompletedThreads = (int) (agentRunData.getNumUsers() - count); if (isDebug() || count < 10) { LOG.info(LogUtil .getLogMessage("User thread finished... Remaining->" + currentUsers, LogEventType.System)); } } public WatsAgentStatusResponse getStats() { int ramp = (agentRunData.getNumUsers() - agentRunData.getNumStartUsers()); if (ramp > 0) { ramp = (int) (agentRunData.getRampTime() - (agentRunData.getRampTime() * currentNumThreads) / (agentRunData.getNumUsers() - agentRunData.getNumStartUsers())); } return new WatsAgentStatusResponse(System.currentTimeMillis() - startTime, validationFailures.getValidationKills(), validationFailures.getValidationAborts(), validationFailures.getValidationGotos(), validationFailures.getValidationSkips(), validationFailures.getValidationSkipGroups(), validationFailures.getValidationRestarts(), currentUsers, agentRunData.getNumUsers(), ramp); } public synchronized void threadStarted() { currentNumThreads++; currentUsers++; } public void setTestPlans(List<String> scripts) { testPlanXmls = scripts; for (String script : scripts) { LOG.debug(script); } } public boolean isDebug() { return DEBUG; } /** * @return the instanceId */ public String getInstanceId() { return instanceId; } public long getSimulationEndTimeMillis() { return getStartTime() + agentRunData.getSimulationTime(); } public boolean hasMetSimulationTime() { boolean ret = false; if (agentRunData.getSimulationTime() > 0) { long currentTime = System.currentTimeMillis(); if (currentTime > getSimulationEndTimeMillis()) { if (!loggedSimTime) { LOG.info(LogUtil.getLogMessage("Simulation time met", LogEventType.System)); loggedSimTime = true; } ret = true; } } return ret; } public long getStartTime() { return startTime; } public long getMaxSimulationEndTimeMillis() { return getSimulationEndTimeMillis() + tankConfig.getAgentConfig().getOverSimulationMaxTime(); } /** * check the agent threads if simulation time has been met. */ public void checkAgentThreads() { int activeCount = threadGroup.activeCount(); Thread[] threads = new Thread[activeCount]; threadGroup.enumerate(threads); int activeThreads = 0; for (Thread t : threads) { if (t != null) { if (t.getState() == Thread.State.TIMED_WAITING || t.getState() == Thread.State.WAITING) { activeThreads++; } } } LOG.info(LogUtil.getLogMessage("Have " + activeThreads + " of " + activeCount + " active Threads in thread group " + threadGroup.getName(), LogEventType.System)); if (agentRunData.getSimulationTime() != 0 && hasMetSimulationTime() && doneSignal.getCount() != 0) { boolean exceededTimeLimit = System.currentTimeMillis() > getMaxSimulationEndTimeMillis(); if (exceededTimeLimit) { LOG.info(LogUtil.getLogMessage("Max simulation time has been met and there are " + doneSignal.getCount() + " threads not reporting done.")); for (Thread t : sessionThreads) { if (t.isAlive()) { if (exceededTimeLimit) { LOG.warn(LogUtil.getLogMessage("thread " + t.getName() + '-' + t.getId() + " is still running with a State of " + t.getState().name(), LogEventType.System)); t.interrupt(); doneSignal.countDown(); } } } } } } /** * @param cmd */ public void setCommand(WatsAgentCommand newCommand) { if (cmd != WatsAgentCommand.stop) { cmd = newCommand; LOG.info(LogUtil.getLogMessage("Got new Command: " + newCommand + " with " + currentNumThreads + " User Threads running.", LogEventType.System)); if (cmd == WatsAgentCommand.stop || cmd == WatsAgentCommand.pause || cmd == WatsAgentCommand.pause_ramp) { APIMonitor.setJobStatus(cmd == WatsAgentCommand.stop ? JobStatus.Stopped : cmd == WatsAgentCommand.pause ? JobStatus.Paused : JobStatus.RampPaused); if (cmd == WatsAgentCommand.pause) { for (Thread t : sessionThreads) { t.interrupt(); } } } else if (cmd == WatsAgentCommand.resume_ramp || cmd == WatsAgentCommand.run) { APIMonitor.setJobStatus(JobStatus.Running); } } } /** * @return the cmd */ public WatsAgentCommand getCmd() { return cmd; } public void queueTimingResult(TankResult result) { if (logTiming) { results.add(result); //if (results.size() >= BATCH_SIZE) { if (send.before(new Date())) { sendBatchToDB(true); c.setTime(new Date()); c.add(Calendar.SECOND, interval); send = new Date(c.getTime().getTime()); } } } private void sendBatchToDB(boolean asynch) { if (results.size() != 0 && logTiming) { final List<TankResult> l = new ArrayList<TankResult>(); synchronized (results) { // logger.info("sendBatchToDB(" + tableName + "); sending " + results.size() + " results."); l.addAll(results); results.clear(); } resultsReporter .sendTimingResults(getAgentRunData().getJobId(), getAgentRunData().getInstanceId(), l, false); } } /** * @return */ public TankConfig getTankConfig() { return tankConfig; } /** * @return the flowControllerTemplate */ public FlowController getFlowControllerTemplate() { return flowControllerTemplate; } /** * @param flowControllerTemplate * the flowControllerTemplate to set */ public void setFlowControllerTemplate(FlowController flowControllerTemplate) { this.flowControllerTemplate = flowControllerTemplate; } public FlowController getFlowController(Long threadId) { FlowController ret = controllerMap.get(threadId); if (ret == null) { ret = flowControllerTemplate.cloneController(); controllerMap.put(threadId, ret); } return ret; } /** * @return the started */ public boolean isStarted() { return started; } /** * @return the agentRunData */ public AgentRunData getAgentRunData() { return agentRunData; } public void setDebug(boolean b) { DEBUG = true; } /** * @return the resultsReporter */ public ResultsReporter getResultsReporter() { return resultsReporter; } /** * @return the tankHttpClientClass */ public String getTankHttpClientClass() { return tankHttpClientClass; } /** * @param tankHttpClientClass the tankHttpClientClass to set */ public void setTankHttpClientClass(String tankHttpClientClass) { this.tankHttpClientClass = tankHttpClientClass; } }