package com.intuit.tank.project; /* * #%L * JSF Support Beans * %% * 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.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; 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.common.ScriptAssignment; import com.intuit.tank.common.ScriptUtil; import com.intuit.tank.dao.ScriptDao; import com.intuit.tank.project.Script; import com.intuit.tank.project.ScriptGroup; import com.intuit.tank.project.ScriptGroupStep; import com.intuit.tank.project.ScriptStep; import com.intuit.tank.project.TestPlan; import com.intuit.tank.vm.common.TankConstants; import com.intuit.tank.vm.common.util.MethodTimer; import com.intuit.tank.vm.settings.TankConfig; import com.intuit.tank.vm.settings.TimeUtil; public class JobValidator { private static final Logger LOG = LogManager.getLogger(JobValidator.class); private Map<String, Set<String>> declaredVariables = new HashMap<String, Set<String>>(); private Map<String, Set<String>> assignments = new HashMap<String, Set<String>>(); private Set<String> usedVariables = new HashSet<String>(); private Set<String> orphanedVariables = new HashSet<String>(); private Set<String> superfluousVariables = new HashSet<String>(); private List<ScriptWrapper> scripts = new ArrayList<ScriptWrapper>(); private Map<String, Long> expectedDuration = new HashMap<String, Long>(); private boolean valid; private boolean processAssignments = false; private Set<String> bestPracticeViolations = new HashSet<String>(); private Set<String> dataFiles = new HashSet<String>(); public JobValidator(@Nonnull List<TestPlan> testplans, @Nonnull Map<String, String> globalVariables) { this(testplans, globalVariables, false); } public JobValidator(@Nonnull List<TestPlan> testplans, @Nonnull Map<String, String> globalVariables, boolean processAssignements) { this.processAssignments = processAssignements; for (Entry<String, String> entry : globalVariables.entrySet()) { putVariable(this.declaredVariables, entry.getKey(), entry.getValue(), "project"); } extractScripts(testplans); processScripts(new HashMap<String, String>(globalVariables)); } public JobValidator(@Nonnull Script s) { this.scripts.add(new ScriptWrapper(s, 1, s.getName(), s.getName())); processAssignments = true; processScripts(new HashMap<String, String>()); } public boolean isValid() { return valid; } public Set<String> getDataFiles() { return dataFiles; } public Set<String> getBestPracticeViolations() { return bestPracticeViolations; } public Map<String, Set<String>> getAssignments() { return assignments; } public Map<String, Set<String>> getDeclaredVariables() { return declaredVariables; } public Set<String> getUsedVariables() { return usedVariables; } public boolean isOrphaned(String var) { return orphanedVariables.contains(var); } public boolean isProcessAssignements() { return this.processAssignments; } public boolean isSuperfluous(String var) { return superfluousVariables.contains(var); } public Set<String> getOrphanedVariables() { return orphanedVariables; } public Set<String> getSuperfluousVariables() { return superfluousVariables; } public long getDurationMs(String group) { Long duration = expectedDuration.get(group); return duration != null ? duration.longValue() : 0L; } public String getDuration(String group) { Long duration = expectedDuration.get(group); return TimeUtil.toTimeString(duration != null ? duration.longValue() : 0); } public long getExpectedTime(String group) { Long duration = expectedDuration.get(group); return duration != null ? duration.longValue() : 0; } private void putVariable(Map<String, Set<String>> map, String key, String value, String declarer) { Set<String> set = map.get(key); if (set == null) { set = new HashSet<String>(); map.put(key, set); } set.add(declarer + ":: " + value); } private void extractScripts(List<TestPlan> testplans) { ScriptDao scriptDao = new ScriptDao(); for (TestPlan plan : testplans) { for (ScriptGroup group : plan.getScriptGroups()) { for (ScriptGroupStep s : group.getScriptGroupSteps()) { int loop = group.getLoop() * s.getLoop(); Script script = scriptDao.loadScriptSteps(s.getScript()); scripts.add(new ScriptWrapper(script, loop, plan.getName(), plan.getName() + "::" + group.getName() + "::" + script.getName())); } } } } private void processScripts(Map<String, String> globalVariables) { MethodTimer mt = new MethodTimer(LOG, this.getClass(), "processScripts"); mt.start(); TankConfig tankConfig = new TankConfig(); boolean hasLoggingKeys = false; for (ScriptWrapper wrapper : scripts) { long milis = 0; Script s = wrapper.script; boolean hasRequest = false; for (ScriptStep step : s.getScriptSteps()) { if (step.getType().equals("request")) { hasRequest = true; } else if (hasRequest && step.getType().equalsIgnoreCase("variable")) { bestPracticeViolations .add("  Rule: Declare variables before request.<br/>    Script " + s.getName() + " declares variable '" + step.getData().iterator().next().getKey() + "' at index " + step.getStepIndex()); } if (StringUtils.isNotBlank(step.getLoggingKey())) { hasLoggingKeys = true; } String dataFile = ScriptUtil.getDataFileUse(step); if (dataFile != null) { String stripped = StringUtils.strip(dataFile, "'\""); dataFiles.add(stripped); if (!stripped.equals(dataFile)) { bestPracticeViolations .add("  Rule: Do not hard Code Data File names.<br/>    Script " + s.getName() + " uses a hard coded name for the data file '" + stripped + "' at index " + step.getStepIndex()); } else if (dataFile.equalsIgnoreCase(TankConstants.DEFAULT_CSV_FILE_NAME)) { bestPracticeViolations .add("  Rule: Explicitly define Data File names.<br/>    Script " + s.getName() + " uses the default data file 'csv-data.txt' at index " + step.getStepIndex()); } } milis += ScriptUtil.calculateStepDuration(step, globalVariables, tankConfig); for (Entry<String, String> entry : ScriptUtil.getDeclaredVariables(step).entrySet()) { putVariable(this.declaredVariables, entry.getKey(), entry.getValue(), wrapper.location); } usedVariables.addAll(ScriptUtil.getUsedVariables(step)); // if (processAssignments) { for (ScriptAssignment assignment : ScriptUtil.getAssignments(step)) { putVariable(this.assignments, assignment.getVariable(), assignment.getAssignemnt(), s.getName() + "[" + assignment.getScriptIndex() + "]"); } usedVariables.addAll(this.assignments.keySet()); // } } addDuration(wrapper.groupName, wrapper.loop, milis); } if (!hasLoggingKeys) { bestPracticeViolations .add("  Rule: No Logging Keys.<br/>    No Logging keys are defined"); } this.orphanedVariables.addAll(usedVariables); for (String s : declaredVariables.keySet()) { orphanedVariables.remove(s); } for (String s : assignments.keySet()) { orphanedVariables.remove(s); } this.superfluousVariables.addAll(declaredVariables.keySet()); this.superfluousVariables.addAll(assignments.keySet()); for (String s : usedVariables) { superfluousVariables.remove(s); } mt.endAndLog(); } private void addDuration(String groupName, int loop, long milis) { Long val = this.expectedDuration.get(groupName); long l = val != null ? val.longValue() : 0L; l += milis * loop; expectedDuration.put(groupName, l); } private static class ScriptWrapper { private Script script; private String location; private String groupName; private int loop; public ScriptWrapper(Script script, int loop, String groupName, String location) { super(); this.script = script; this.location = location; this.groupName = groupName; this.loop = loop; } } }