Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#544 Eliminate Testcase Mapping for Basic Setups #560

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -720,5 +720,10 @@
<version>3.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
</dependencies>
</project>
36 changes: 34 additions & 2 deletions src/main/java/com/xceptance/common/lang/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
package com.xceptance.common.lang;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
Expand Down Expand Up @@ -47,8 +51,8 @@ public static String crc32(final String s)
}

/**
* Replaces the first substring of this string that matches the given <a
* href="../util/regex/Pattern.html#sum">regular expression</a> with the given replacement. This is a replacement
* Replaces the first substring of this string that matches the given
* <a href="../util/regex/Pattern.html#sum">regular expression</a> with the given replacement. This is a replacement
* method, that speeds up the processing due to internal caching of the compiled regular expression.
*
* @param str
Expand Down Expand Up @@ -147,6 +151,34 @@ public static String[] split(final String str, final String regex)
return split(str, regex, 0);
}

/**
* Join the given elements into a String separated by the given delimiter. The given limit determines how many
* elements from the collection will be joined. The given suffix will be added to the resulting String if there are
* more elements than the limit states.
*
* @param delimiter
* the delimiting char sequence
* @param elements
* the elements to join
* @param limit
* the max number of elements that will be joined
* @param suffix
* the suffix to add to the resulting String if the limit was exceeded
* @return the resulting String
*/
public static String join(final CharSequence delimiter, final List<? extends CharSequence> elements, final int limit,
final CharSequence suffix)
{
if (elements.size() > limit)
{
return String.join(delimiter, elements.subList(0, limit)) + suffix;
}
else
{
return String.join(delimiter, elements);
}
}

/**
* Default constructor. Declared private to prevent external instantiation.
*/
Expand Down
130 changes: 102 additions & 28 deletions src/main/java/com/xceptance/xlt/mastercontroller/MasterController.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration.JupIOFactory;
import org.apache.commons.configuration2.io.FileHandler;
import com.xceptance.xlt.util.PropertyFileHandler;
import com.xceptance.xlt.util.TestCaseMapper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;
Expand Down Expand Up @@ -712,6 +711,14 @@ public boolean startAgents(final String testCaseName) throws AgentControllerExce
// read load test profile if not already done so before during upload
final File workDir = setUpWorkDir(FILE_FILTER);
currentLoadProfile = getTestProfile(workDir);

final TestCaseMapper testCaseMapper = new TestCaseMapper(currentLoadProfile);
if (!testCaseMapper.getUnmappedTestCaseNames().isEmpty())
{
final Map<String, String> testCaseClassMappings = testCaseMapper.scanForTestCaseClassMappings(workDir);
overwriteTestCaseClassMappings(workDir, testCaseClassMappings, FILE_FILTER);
currentLoadProfile.setTestCaseClassMappings(testCaseClassMappings);
}
}

resetAgentStatuses();
Expand Down Expand Up @@ -881,13 +888,25 @@ public void updateAgentFiles() throws AgentControllerException, IOException, Ill
* Optionally copy and manipulate the test suite.
*/
LOG.info("Read target test suite");
final File workDir = setUpWorkDir(FILE_FILTER);
File workDir = setUpWorkDir(FILE_FILTER);
progressPrepare.increaseCount();

/*
* Read the configuration files and build load profile.
*/
currentLoadProfile = getTestProfile(workDir);

/*
* Auto-map test cases to test classes if no mapping was configured.
*/
final TestCaseMapper testCaseMapper = new TestCaseMapper(currentLoadProfile);
if (!testCaseMapper.getUnmappedTestCaseNames().isEmpty())
{
final Map<String, String> autoMappings = testCaseMapper.scanForTestCaseClassMappings(workDir);
workDir = overwriteTestCaseClassMappings(workDir, autoMappings, FILE_FILTER);
currentLoadProfile.setTestCaseClassMappings(autoMappings);
}

progressPrepare.increaseCount();

if (currentLoadProfile.getActiveTestCaseNames().size() <= 0)
Expand Down Expand Up @@ -952,31 +971,86 @@ private File setUpWorkDir(final FileFilter fileFilter)
}
else
{
try
{
// create a new sub directory in the temp directory
workDir = File.createTempFile("xlt-", "", tempDirectory);
org.apache.commons.io.FileUtils.forceDelete(workDir);
org.apache.commons.io.FileUtils.forceMkdir(workDir);

// copy the test suite
org.apache.commons.io.FileUtils.copyDirectory(agentFilesDirectory, workDir, fileFilter);

// enter the test properties file into project.properties
final File projectPropertiesFile = new File(new File(workDir, "config"), "project.properties");
final PropertiesConfiguration config = new PropertiesConfiguration();
config.setIOFactory(new JupIOFactory()); // for better compatibility with java.util.Properties (GH#144)
final FileHandler fileHandler = new FileHandler(config);

fileHandler.load(projectPropertiesFile);
config.setProperty(XltConstants.TEST_PROPERTIES_FILE_PATH_PROPERTY, propertiesFileName);
fileHandler.save(projectPropertiesFile);
}
catch (final Exception e)
{
throw new RuntimeException("Failed to make a copy of the agent files", e);
}
workDir = copyAgentDirectoryToTemp(fileFilter);

// enter the test properties file into project.properties
final File projectPropertiesFile = new File(new File(workDir, XltConstants.CONFIG_DIR_NAME),
XltConstants.PROJECT_PROPERTY_FILENAME);
final PropertyFileHandler propertyFileHandler = new PropertyFileHandler(projectPropertiesFile);
propertyFileHandler.setProperty(XltConstants.TEST_PROPERTIES_FILE_PATH_PROPERTY, propertiesFileName);
}
return workDir;
}

/**
* Make a temp copy of the agent files directory if necessary and write the given test case and class mappings to
* the "project.properties".
*
* @param currentWorkDir
* the current working directory
* @param testCaseClassMappings
* the test case and class mappings to set in the properties
* @param fileFilter
* file filter for testsuite
* @return the resulting working directory
*/
private File overwriteTestCaseClassMappings(final File currentWorkDir, final Map<String, String> testCaseClassMappings,
final FileFilter fileFilter)
{
// If we didn't make a temp copy of the agent directory yet, we do so now
final File workDir;
if (currentWorkDir == agentFilesDirectory)
{
workDir = copyAgentDirectoryToTemp(fileFilter);
}
else
{
workDir = currentWorkDir;
}

final Map<String, String> propertyMappings = new HashMap<>();
for (String testCaseName : testCaseClassMappings.keySet())
{
String propertyName = TestLoadProfileConfiguration.PROP_PREFIX_LOAD_TESTS + testCaseName +
TestLoadProfileConfiguration.PROP_SUFFIX_CLASS;
propertyMappings.put(propertyName, testCaseClassMappings.get(testCaseName));
}

// Set mappings in project.properties
final File projectPropertiesFile = new File(new File(workDir, XltConstants.CONFIG_DIR_NAME),
XltConstants.PROJECT_PROPERTY_FILENAME);
final PropertyFileHandler propertyFileHandler = new PropertyFileHandler(projectPropertiesFile);
propertyFileHandler.setProperties(propertyMappings);

return workDir;
}

/**
* Copy contents of agent files directory to new temp directory.
*
* @param fileFilter
* file filter for testsuite
* @return the resulting temp directory
*/
private File copyAgentDirectoryToTemp(final FileFilter fileFilter)
{
final File workDir;

try
{
// create a new sub directory in the temp directory
workDir = File.createTempFile("xlt-", "", tempDirectory);
org.apache.commons.io.FileUtils.forceDelete(workDir);
org.apache.commons.io.FileUtils.forceMkdir(workDir);

// copy the test suite
org.apache.commons.io.FileUtils.copyDirectory(agentFilesDirectory, workDir, fileFilter);
}
catch (final Exception e)
{
throw new RuntimeException("Failed to make a copy of the agent files", e);
}

return workDir;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class TestLoadProfileConfiguration extends AbstractConfiguration
/**
* property suffix to set the class of a test
*/
private static final String PROP_SUFFIX_CLASS = ".class";
public static final String PROP_SUFFIX_CLASS = ".class";

/**
* property suffix to set the initial delay of a test
Expand Down Expand Up @@ -142,7 +142,7 @@ public class TestLoadProfileConfiguration extends AbstractConfiguration
/**
* property prefix to set the test cases of the load test
*/
private static final String PROP_PREFIX_LOAD_TESTS = PROP_ACTIVE_LOAD_TESTS + ".";
public static final String PROP_PREFIX_LOAD_TESTS = PROP_ACTIVE_LOAD_TESTS + ".";

/**
* property suffix to set the default value of all tests
Expand Down Expand Up @@ -416,9 +416,9 @@ private void configure(final String[] testCaseNames, final Map<String, TestCaseL
.orElse(defaultConfiguration.getActionThinkTimeDeviation());

// check mandatory parameters
if (className == null || className.isBlank())
if (className != null && className.isBlank())
{
throw new XltException("No test class specified for test case '" + testCaseName + "'.");
throw new XltException("Test class specified for test case '" + testCaseName + "', but the value is empty.");
}

if (measurementPeriod == 0)
Expand Down Expand Up @@ -703,6 +703,20 @@ private int[][] getDoubleLoadFunction(final String propertyName, final int[][] d
return loadFunction;
}

/**
* Set the test classes in the test case specific configurations.
*
* @param testCaseClassMappings
* the map of test case names and their associated test class names to set
*/
public void setTestCaseClassMappings(final Map<String, String> testCaseClassMappings)
{
for (final String testCaseName : testCaseClassMappings.keySet())
{
this.loadTestConfigs.get(testCaseName).setTestCaseClassName(testCaseClassMappings.get(testCaseName));
}
}

private static class DefaultTestCaseLoadProfileConfiguration extends TestCaseLoadProfileConfiguration
{
private int rampUpSteadyPeriod;
Expand Down
72 changes: 72 additions & 0 deletions src/main/java/com/xceptance/xlt/util/PropertyFileHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.xceptance.xlt.util;

import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.io.FileHandler;

import java.io.File;
import java.util.Map;

/**
* File handler for setting name-value pairs in a property file.
*/
public class PropertyFileHandler
{
private final File propertyFile;

/**
* Creates a new property file handler for editing the given property file.
*
* @param propertyFile
* the property file to edit
*/
public PropertyFileHandler(File propertyFile)
{
this.propertyFile = propertyFile;
}

/**
* Set the property with the given name to the given value. If the property with the given name already exists in
* the file it will be replaced. Other properties will remain unchanged.
*
* @param propertyName
* property name
* @param propertyValue
* property value
*/
public void setProperty(final String propertyName, final String propertyValue)
{
setProperties(Map.of(propertyName, propertyValue));
}

/**
* Set the properties as described by the given name-value pairs. If a property with any of the given names already
* exists in the file it will be replaced. Other properties will remain unchanged.
*
* @param propertyMap
* map of property names and their associated values
*/
public void setProperties(final Map<String, String> propertyMap)
{
final PropertiesConfiguration config = new PropertiesConfiguration();
config.setIOFactory(new PropertiesConfiguration.JupIOFactory()); // for better compatibility with
// java.util.Properties (GH#144)
final FileHandler fileHandler = new FileHandler(config);

try
{
fileHandler.load(this.propertyFile);

for (final String propertyName : propertyMap.keySet())
{
config.setProperty(propertyName, propertyMap.get(propertyName));
}

fileHandler.save(this.propertyFile);
}
catch (Exception e)
{
throw new RuntimeException("Failed to update the properties in '" + propertyFile.getName() + "'.", e);
}

}
}
Loading