package com.intuit.tank.util; /* * #%L * Common * %% * 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.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.intuit.tank.util.TestParameterContainer.Builder; import com.intuit.tank.vm.settings.TimeUtil; import de.congrace.exp4j.Calculable; import de.congrace.exp4j.ExpressionBuilder; /** * * TestParamUtil utility class for evaluating test parameters in the syntax of 2RT + 10m. * * @author dangleton * */ public final class TestParamUtil { private static final Logger LOG = LogManager.getLogger(TestParamUtil.class); private static final String REGEX = "(\\(*[\\.,\\d]+\\)*)(\\(*[e,r,s]t\\)*)"; private static final String ALT_REGEX = "(\\(*[e,r,s]t\\)*)(\\(*[\\.,\\d]+\\)*)"; private static final String ESTIMATED_RUN_TIME = "et"; private static final String RAMP_TIME = "rt"; private static final String SIMULATION_TIME = "st"; private static final long TEST_VALUE = 30000L; /** * private constructor to implement util pattern */ private TestParamUtil() { } /** * extracts the ramp and simulation time from the given values. * * @param executionTime * the calculated execution time. * @param rampTimeString * the expression for the ramp time * @param simulationTimeString * the expresssion for the simulation time * @return {@link TestParameterContainer} contianing the values. * @throws IllegalArgumentException * if there is an issue evaluating the expressions or there is a cyclic dependency. */ public static TestParameterContainer evaluateTestTimes(long executionTime, String rampTimeString, String simulationTimeString) throws IllegalArgumentException { boolean rampComplete = false; long rampTime = 0; long simTime = 0; Builder builder = TestParameterContainer.builder(); if (StringUtils.isNotBlank(rampTimeString)) { if (!rampTimeString.toLowerCase().contains(SIMULATION_TIME)) { rampTime = evaluateExpression(rampTimeString, executionTime, simTime, rampTime); builder.withRampTime(rampTime); rampComplete = true; } } if (StringUtils.isNotBlank(simulationTimeString)) { if (rampTimeString.toLowerCase().contains(RAMP_TIME) && !rampComplete) { throw new IllegalArgumentException("cyclic dependeny of ramp time and simulation time."); } simTime = evaluateExpression(simulationTimeString, executionTime, simTime, rampTime); builder.withSimulationTime(simTime); } if (!rampComplete && StringUtils.isNotBlank(rampTimeString)) { rampTime = evaluateExpression(rampTimeString, executionTime, simTime, rampTime); builder.withRampTime(rampTime); } return builder.build(); } /** * Evaluates the expression provided. * * @param value * the value to evaluate * @param executionTime * the execution time * @param simulationTime * the simulationTime * @param rampTime * the rampTime * @return the long value of evaluating the expression. * @throws IllegalArgumentException * if there is an issue evaluating the expression. */ public static long evaluateExpression(String value, long executionTime, long simulationTime, long rampTime) throws IllegalArgumentException { if (StringUtils.isBlank(value)) { throw new IllegalArgumentException("Expression is either null or empty."); } String expression = normalizeExpression(value); try { Calculable calc = new ExpressionBuilder(expression) .withVariable(ESTIMATED_RUN_TIME, executionTime) .withVariable(SIMULATION_TIME, simulationTime) .withVariable(RAMP_TIME, rampTime) .build(); long result = Math.round(calc.calculate()); LOG.debug(value + " --> " + expression + " = " + Long.toString(result)); return result; } catch (Exception e) { LOG.warn(value + " is not a valid expression."); throw new IllegalArgumentException(e); } } /** * checks to see if the expressin is valid. * * @param value * the expression to evaluate * @return true if the expression can be evaluated. */ public static final boolean isValidExpression(@Nonnull String value) { boolean ret = StringUtils.isNotBlank(value); if (ret) { try { evaluateExpression(value, TEST_VALUE, TEST_VALUE, TEST_VALUE); } catch (Exception e) { ret = false; } } return ret; } private static String normalizeExpression(String expression) { String ret = expression; if (StringUtils.isNotBlank(ret)) { String[] args = StringUtils.split(expression); StringBuilder timeArg = new StringBuilder(); StringBuilder result = new StringBuilder(); for (String arg : args) { if (arg.toLowerCase().endsWith("m") || arg.toLowerCase().endsWith("s") || arg.toLowerCase().endsWith("h") || arg.toLowerCase().endsWith("d")) { // its a time string addArgToBuilder(timeArg, arg); } else { if (timeArg.length() != 0) { long time = TimeUtil.parseTimeString(timeArg.toString()); addArgToBuilder(result, Long.toString(time)); timeArg = new StringBuilder(); } addArgToBuilder(result, normalizeArg(arg.toLowerCase())); } } if (timeArg.length() != 0) { long time = TimeUtil.parseTimeString(timeArg.toString()); addArgToBuilder(result, Long.toString(time)); timeArg = new StringBuilder(); } ret = result.toString(); } return ret; } private static String normalizeArg(String s) { Pattern p = Pattern.compile(REGEX); Matcher matcher = p.matcher(s); Pattern p1 = Pattern.compile(ALT_REGEX); Matcher matcher1 = p1.matcher(s); if (matcher.matches()) { s = matcher.group(1) + " * " + matcher.group(2); } else if (matcher1.matches()) { s = matcher1.group(1) + " * " + matcher1.group(2); } if (s.startsWith(".")) { s = "0" + s; } return s; } private static void addArgToBuilder(StringBuilder sb, String s) { if (sb.length() != 0) { sb.append(" "); } sb.append(s); } }