removed timing considerations from test sorting

This commit is contained in:
adamopolous 2019-09-17 07:57:57 -04:00
parent 6174b1e5ae
commit 8df7df2e72
3 changed files with 140 additions and 60 deletions

View file

@ -367,6 +367,15 @@ def createTestTask(Project subproject, String testType, String bucketName, int t
group "test"
testClassesDirs = files subproject.sourceSets["$testType"].output.classesDirs
classpath = subproject.sourceSets["$testType"].runtimeClasspath
logger.info("********TEST CREATION")
logger.info(" " + subproject)
logger.info(" " + testType)
logger.info(" " + bucketName)
logger.info(" " + taskNameCounter)
logger.info(" " + classesList)
logger.info(" " + classesListPosition)
logger.info(" " + numMaxParallelForks)
maxParallelForks = numMaxParallelForks
@ -419,9 +428,9 @@ configure(subprojects.findAll {parallelMode == true}) { subproject ->
if (!shouldSkipTestTaskCreation(subproject)) {
logger.info("parallelCombinedTestReport: Creating 'test' tasks for " + subproject.name + " subproject.")
Map<String,Map> testMap = getTestsForSubProject(subproject.sourceSets.test.java)
Map<String,List> testMap = getTestsForSubProject(subproject.sourceSets.test.java)
for (Map.Entry<String,Map> classMap : testMap.entrySet()) {
for (Map.Entry<String,List> classMap : testMap.entrySet()) {
String bucketName = classMap.getKey();
@ -429,12 +438,10 @@ configure(subprojects.findAll {parallelMode == true}) { subproject ->
int taskNameCounter = 1 // task suffix
int numMaxParallelForks = 40 // unit tests are fast; 40 seems to be a reasonable number
Map<String,Long> tests = classMap.getValue();
def sorted = tests.sort { a, b -> b.value <=> a.value };
List<String> classesList = new ArrayList(sorted.keySet());
List<String> tests = classMap.getValue();
while (classesListPosition < classesList.size()) {
createTestTask(subproject, "test", bucketName, taskNameCounter, classesList, classesListPosition, numMaxParallelForks)
while (classesListPosition < tests.size()) {
createTestTask(subproject, "test", bucketName, taskNameCounter, tests, classesListPosition, numMaxParallelForks)
classesListPosition+=numMaxParallelForks
taskNameCounter+=1; // "test_1_appConfig", "test_2_appConfig, etc.
}
@ -444,10 +451,12 @@ configure(subprojects.findAll {parallelMode == true}) { subproject ->
if (!shouldSkipIntegrationTestTaskCreation(subproject)) {
logger.info("parallelCombinedTestReport: Creating 'integrationTest' tasks for " + subproject.name + " subproject.")
Map<String,Map> testMap = getTestsForSubProject(subproject.sourceSets.integrationTest.java)
Map<String,List> testMap = getTestsForSubProject(subproject.sourceSets.integrationTest.java)
logger.info("====CREATING TASKS FOR: " + subproject)
for (Map.Entry<String,Map> classMap : testMap.entrySet()) {
for (Map.Entry<String,List> classMap : testMap.entrySet()) {
logger.info(" bucket: " + classMap.getKey())
String bucketName = classMap.getKey();
int classesListPosition = 0 // current position in classesList
@ -458,12 +467,12 @@ configure(subprojects.findAll {parallelMode == true}) { subproject ->
// 20 seems like a good balance of throughput vs resource usage for ghidratest server.
int numMaxParallelForks = 20
Map<String,Long> tests = classMap.getValue();
def sorted = tests.sort { a, b -> b.value <=> a.value };
List<String> classesList = new ArrayList(sorted.keySet());
List<String> tests = classMap.getValue();
while (classesListPosition < classesList.size()) {
createTestTask(subproject, "integrationTest", bucketName, taskNameCounter, classesList, classesListPosition, numMaxParallelForks)
logger.info(" tests: " + tests)
while (classesListPosition < tests.size()) {
createTestTask(subproject, "integrationTest", bucketName, taskNameCounter, tests, classesListPosition, numMaxParallelForks)
classesListPosition+=numMaxParallelForks
taskNameCounter+=1; // "integrationTest_1_appConfig", "integrationTest_2_appConfig, etc.
}

View file

@ -82,6 +82,7 @@ AbstractToolSavingTest
AbstractVersionControlActionTest
AbstractVTCorrelatorTest
AbstractVTMarkupItemTest
CallTreePluginTest
DiffTestAdapter
DWARFTestBase
AbstractSelfSimilarCorrelatorTest

View file

@ -8,6 +8,11 @@ import java.io.*;
// to tests (test name, duration)
ext.testReport = null;
ext.integrationConfigs = new ArrayList<>();
ext.dockingConfigs = new ArrayList<>();
ext.appConfigs = new ArrayList<>();
ext.ghidraConfigs = new ArrayList<>();
/*
* Checks if html test report for an individual test class has a valid name.
*/
@ -67,6 +72,7 @@ long getDurationFromTestReportClass(String fileContents, String fileName) {
*
* eg: GhidraAppConfiguration -> DiffTestTypeAdapter, 0.135s
*/
def Map<String, Map<String, Long>> getTestReport() {
// If we have already created the test report, do not waste time creating
@ -79,10 +85,6 @@ def Map<String, Map<String, Long>> getTestReport() {
testReport = new HashMap<String,Map>();
List<String> integrationConfigs = new ArrayList<>();
List<String> dockingConfigs = new ArrayList<>();
List<String> appConfigs = new ArrayList<>();
List<String> ghidraConfigs = new ArrayList<>();
parseApplicationConfigs(dockingConfigs, integrationConfigs, appConfigs, ghidraConfigs);
File classesReportDir = new File(testTimeParserInputDir)
@ -118,7 +120,6 @@ def Map<String, Map<String, Long>> getTestReport() {
String shortName = fqNameFromTestReport.substring(nameIndex+1);
long durationInMillis = getDurationFromTestReportClass(fileContents, file.name)
File rootDir = project.rootDir.getParentFile();
File foundFile;
fileTree(rootDir.getAbsolutePath()).visit { FileVisitDetails details ->
@ -172,6 +173,12 @@ def Map<String, Map<String, Long>> getTestReport() {
testReport.put("ghidra", ghidraBucket);
testReport.put("unknown", unknownBucket);
logger.debug("integration bucket: " + integrationBucket)
logger.debug("docking bucket: " + dockingBucket)
logger.debug("app bucket: " + appBucket)
logger.debug("ghidra bucket: " + ghidraBucket)
logger.debug("unknown bucket: " + unknownBucket)
logger.debug("getTestReport: Added to testReport: class name = '"
+ fqNameFromTestReport + "' and durationInMillis = '"+ durationInMillis
+"' from " + file.name)
@ -304,7 +311,7 @@ String constructFullyQualifiedClassName(String fileContents, String fileName) {
* Then traverses a test sourceSet for a subproject for a test to include and assigns a duration value.
* Returns a sorted list of test classes for the sourceSet parameter.
*/
def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet) {
def Map<String, List> getTestsForSubProject(SourceDirectorySet sourceDirectorySet) {
def testsForSubProject = new HashMap<String,LinkedHashMap>();
@ -317,9 +324,18 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
logger.debug("getTestsForSubProject: Found " + sourceDirectorySet.files.size()
+ " file(s) in source set to process.")
Map<String,Map> testReports = getTestReport();
assert (testReports != null) : "getTestsForSubProject: testReport should not be null"
//Map<String,Map> testReports = getTestReport();
parseApplicationConfigs(dockingConfigs, integrationConfigs, appConfigs, ghidraConfigs);
//assert (testReports != null) : "getTestsForSubProject: testReport should not be null"
List dockingBucket = new ArrayList<String>();
List integrationBucket = new ArrayList<String>();
List appBucket = new ArrayList<String>();
List ghidraBucket = new ArrayList<String>();
List unknownBucket = new ArrayList<String>();
for (File file : sourceDirectorySet.getFiles()) {
logger.debug("getTestsForSubProject: Found file in sourceSet = " + file.name)
@ -331,7 +347,7 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
}
String fileContents = file.text
// Must not have a Category annotation
if (hasCategoryExcludes(fileContents)) {
logger.debug("getTestsForSubProject: Found category exclude for '"
@ -339,38 +355,100 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
excludedClassFilesCategory++
continue
}
String fqName = constructFullyQualifiedClassName( fileContents, file.name)
boolean foundTest = false;
for (Map.Entry<String,Map> entry : testReports.entrySet()) {
String configName = entry.getKey();
Map<String,Long> tests = entry.getValue();
// Get any extending class so we can see what bucket it belongs to
// Match the word right after "extends", if there is one
Pattern p = Pattern.compile("extends\\W+(\\w+)");
Matcher m = p.matcher(fileContents);
String extendsClass = "";
while (m.find()) {
extendsClass = m.group(1);
break;
}
//String absFilename = file.getAbsolutePath();
// Get full package name of the class - this is what needs to go in the bucket
Pattern p2 = Pattern.compile("package\\s+([a-zA_Z_][\\.\\w]*);");
Matcher m2 = p2.matcher(fileContents);
String packageName = "";
while (m2.find()) {
packageName = m2.group(1);
break;
}
String className = packageName + "." + file.name
className = className.replace(".java", "")
if (tests.containsKey(fqName)) {
foundTest = true;
if (!testsForSubProject.containsKey(configName)) {
Map<String,Map> configToTestMap = new LinkedHashMap<>();
testsForSubProject.put(configName, configToTestMap);
}
Map<String,Long> subTests = testsForSubProject.get(configName);
long duration = tests.get(fqName);
if (duration > 0) {
subTests.put(fqName,duration);
logger.debug("getTestsForSubProject: Adding '" + fqName + "'")
includedClassFilesInTestReport++
}
else {
logger.debug("getTestsForSubProject: Excluding '" + fqName
+ "' because duration from test report is " + duration
+ "ms. Probably because all test methods are @Ignore'd." )
excludedClassAllTestsIgnored++
}
if (extendsClass.isEmpty()) {
unknownBucket.add(className);
}
else {
if (integrationConfigs.contains(extendsClass)) {
integrationBucket.add(className);
}
else if (dockingConfigs.contains(extendsClass)) {
dockingBucket.add(className);
}
else if (appConfigs.contains(extendsClass)) {
appBucket.add(className);
}
else if (ghidraConfigs.contains(extendsClass)) {
ghidraBucket.add(className);
}
else {
unknownBucket.add(className);
}
}
}
testReport = new HashMap<String,List>();
testReport.put("docking", dockingBucket)
testReport.put("integration", integrationBucket)
testReport.put("app", appBucket)
testReport.put("ghidra", ghidraBucket)
testReport.put("unknown", unknownBucket)
logger.debug("integration bucket: " + integrationBucket)
logger.debug("docking bucket: " + dockingBucket)
logger.debug("app bucket: " + appBucket)
logger.debug("ghidra bucket: " + ghidraBucket)
logger.debug("unknown bucket: " + unknownBucket)
return testReport;
/**String fqName = constructFullyQualifiedClassName( fileContents, file.name)
boolean foundTest = false;
for (Map.Entry<String,List> entry : testReport.entrySet()) {
String configName = entry.getKey();
List<String> tests = entry.getValue();
if (tests.contains(fqName)) {
foundTest = true;
if (!testsForSubProject.containsKey(configName)) {
Map<String,Map> configToTestMap = new LinkedHashMap<>();
testsForSubProject.put(configName, configToTestMap);
}
Map<String,Long> subTests = testsForSubProject.get(configName);
long duration = tests.get(fqName);
if (duration > 0) {
subTests.put(fqName,duration);
logger.debug("getTestsForSubProject: Adding '" + fqName + "'")
includedClassFilesInTestReport++
}
else {
logger.debug("getTestsForSubProject: Excluding '" + fqName
+ "' because duration from test report is " + duration
+ "ms. Probably because all test methods are @Ignore'd." )
excludedClassAllTestsIgnored++
}
}
}
if (!foundTest) {
// Don't know what this test is so put it in the "unknown" bucket
if (!testsForSubProject.containsKey("unknown")) {
@ -393,21 +471,13 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
testMap.sort { a, b -> b.value <=> a.value }
}
/* logger.info ("getTestsForSubProject:\n"
+ "\tIncluding " + includedClassFilesInTestReport + " test classes for this sourceSet because they are in the test report.\n"
+ "\tIncluding/bumping " + includedClassFilesNotInTestReport + " not in test report.\n"
+ "\tExcluding "+ excludedClassFilesBadName +" based on name not ending in 'Test' or contains 'Abstract' or 'Suite', " + excludedClassFilesCategory
+ " based on '@Category, " + excludedClassAllTestsIgnored + " because duration = 0ms.\n"
+ "\tReturning sorted list of size "+ sorted.size() + " out of " + sourceDirectorySet.files.size()
+ " total files found in sourceSet.")
*/
int filesProcessed = includedClassFilesNotInTestReport + includedClassFilesInTestReport +
excludedClassFilesBadName + excludedClassFilesCategory + excludedClassAllTestsIgnored
assert sourceDirectorySet.files.size() == filesProcessed : "getTestsForSubProject did not process every file in sourceSet"
return testsForSubProject;
*/
}
/*********************************************************************************