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

View File

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

View File

@ -8,6 +8,11 @@ import java.io.*;
// to tests (test name, duration) // to tests (test name, duration)
ext.testReport = null; 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. * 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 * eg: GhidraAppConfiguration -> DiffTestTypeAdapter, 0.135s
*/ */
def Map<String, Map<String, Long>> getTestReport() { def Map<String, Map<String, Long>> getTestReport() {
// If we have already created the test report, do not waste time creating // 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>(); 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); parseApplicationConfigs(dockingConfigs, integrationConfigs, appConfigs, ghidraConfigs);
File classesReportDir = new File(testTimeParserInputDir) File classesReportDir = new File(testTimeParserInputDir)
@ -118,7 +120,6 @@ def Map<String, Map<String, Long>> getTestReport() {
String shortName = fqNameFromTestReport.substring(nameIndex+1); String shortName = fqNameFromTestReport.substring(nameIndex+1);
long durationInMillis = getDurationFromTestReportClass(fileContents, file.name) long durationInMillis = getDurationFromTestReportClass(fileContents, file.name)
File rootDir = project.rootDir.getParentFile(); File rootDir = project.rootDir.getParentFile();
File foundFile; File foundFile;
fileTree(rootDir.getAbsolutePath()).visit { FileVisitDetails details -> fileTree(rootDir.getAbsolutePath()).visit { FileVisitDetails details ->
@ -172,6 +173,12 @@ def Map<String, Map<String, Long>> getTestReport() {
testReport.put("ghidra", ghidraBucket); testReport.put("ghidra", ghidraBucket);
testReport.put("unknown", unknownBucket); 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 = '" logger.debug("getTestReport: Added to testReport: class name = '"
+ fqNameFromTestReport + "' and durationInMillis = '"+ durationInMillis + fqNameFromTestReport + "' and durationInMillis = '"+ durationInMillis
+"' from " + file.name) +"' 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. * 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. * 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>(); def testsForSubProject = new HashMap<String,LinkedHashMap>();
@ -317,9 +324,18 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
logger.debug("getTestsForSubProject: Found " + sourceDirectorySet.files.size() logger.debug("getTestsForSubProject: Found " + sourceDirectorySet.files.size()
+ " file(s) in source set to process.") + " file(s) in source set to process.")
Map<String,Map> testReports = getTestReport(); //Map<String,Map> testReports = getTestReport();
assert (testReports != null) : "getTestsForSubProject: testReport should not be null"
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()) { for (File file : sourceDirectorySet.getFiles()) {
logger.debug("getTestsForSubProject: Found file in sourceSet = " + file.name) logger.debug("getTestsForSubProject: Found file in sourceSet = " + file.name)
@ -331,7 +347,7 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
} }
String fileContents = file.text String fileContents = file.text
// Must not have a Category annotation // Must not have a Category annotation
if (hasCategoryExcludes(fileContents)) { if (hasCategoryExcludes(fileContents)) {
logger.debug("getTestsForSubProject: Found category exclude for '" logger.debug("getTestsForSubProject: Found category exclude for '"
@ -339,38 +355,100 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
excludedClassFilesCategory++ excludedClassFilesCategory++
continue continue
} }
String fqName = constructFullyQualifiedClassName( fileContents, file.name)
boolean foundTest = false; // Get any extending class so we can see what bucket it belongs to
for (Map.Entry<String,Map> entry : testReports.entrySet()) { // Match the word right after "extends", if there is one
String configName = entry.getKey(); Pattern p = Pattern.compile("extends\\W+(\\w+)");
Map<String,Long> tests = entry.getValue(); 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)) { if (extendsClass.isEmpty()) {
foundTest = true; unknownBucket.add(className);
if (!testsForSubProject.containsKey(configName)) { }
Map<String,Map> configToTestMap = new LinkedHashMap<>(); else {
testsForSubProject.put(configName, configToTestMap); if (integrationConfigs.contains(extendsClass)) {
} integrationBucket.add(className);
}
Map<String,Long> subTests = testsForSubProject.get(configName); else if (dockingConfigs.contains(extendsClass)) {
dockingBucket.add(className);
long duration = tests.get(fqName); }
else if (appConfigs.contains(extendsClass)) {
if (duration > 0) { appBucket.add(className);
subTests.put(fqName,duration); }
logger.debug("getTestsForSubProject: Adding '" + fqName + "'") else if (ghidraConfigs.contains(extendsClass)) {
includedClassFilesInTestReport++ ghidraBucket.add(className);
} }
else { else {
logger.debug("getTestsForSubProject: Excluding '" + fqName unknownBucket.add(className);
+ "' because duration from test report is " + duration
+ "ms. Probably because all test methods are @Ignore'd." )
excludedClassAllTestsIgnored++
}
} }
} }
}
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) { if (!foundTest) {
// Don't know what this test is so put it in the "unknown" bucket // Don't know what this test is so put it in the "unknown" bucket
if (!testsForSubProject.containsKey("unknown")) { if (!testsForSubProject.containsKey("unknown")) {
@ -393,21 +471,13 @@ def Map<String, Map> getTestsForSubProject(SourceDirectorySet sourceDirectorySet
testMap.sort { a, b -> b.value <=> a.value } 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 + int filesProcessed = includedClassFilesNotInTestReport + includedClassFilesInTestReport +
excludedClassFilesBadName + excludedClassFilesCategory + excludedClassAllTestsIgnored excludedClassFilesBadName + excludedClassFilesCategory + excludedClassAllTestsIgnored
assert sourceDirectorySet.files.size() == filesProcessed : "getTestsForSubProject did not process every file in sourceSet" assert sourceDirectorySet.files.size() == filesProcessed : "getTestsForSubProject did not process every file in sourceSet"
return testsForSubProject; return testsForSubProject;
*/
} }
/********************************************************************************* /*********************************************************************************