org.evosuite.continuous.ContinuousTestGeneration Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see .
*/
package org.evosuite.continuous;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.evosuite.Properties;
import org.evosuite.continuous.job.JobDefinition;
import org.evosuite.continuous.job.JobExecutor;
import org.evosuite.continuous.job.JobScheduler;
import org.evosuite.continuous.persistency.StorageManager;
import org.evosuite.continuous.project.ProjectAnalyzer;
import org.evosuite.continuous.project.ProjectStaticData;
import org.evosuite.utils.FileIOUtils;
import org.evosuite.xsd.Project;
import org.evosuite.xsd.ProjectUtil;
/**
*
* This is the main entry point for the new
* paradigm "Continuous Test Generation" (CTG).
* This can be called directly from EvoSuite for
* experiment reasons, but its usage for practitioners
* will be based on build environments like Maven/Ant
* and continuous integration environments like
* Jenkins/Hudson/Bamboo
*
*
*
* In a nutshell, the idea is for a project to keep track/store
* the best test suite for each class in the project.
* Each time CTG is run (and can be run continuously), we try
* to generate test suites for classes we haven't addressed
* yet, and we try to improve the current ones (by seeding).
* Benefits are for example:
*
* - No need to download EvoSuite. This is done automatically
* with Maven
* - Smart allocation of search budget among classes with
* different size/difficulty
* - Very easily configurable to run 24/7, with reports on entire
* project
* - Possibility to reuse test cases/data from one class to
* help generation of test suites for new classes
* - Can automatically check from repository which classes
* have been modified, and concentrate search on them
*
*
*
*
* CTG can also be configured to "call home".
* This will be useful to see how EvoSuite is used in practice.
*
*
*
*
* TODO we should also have an option "regression" to run
* current test suites, and see if any fails.
* Even if do not want to explicitly do regression, we might still
* have to run old test cases, as failing ones should be (re)moved and
* labelled as "regression-failing"
*
*
*
* TODO need also option to automatically commit to repository any new, better test
*
* @author arcuri
*
*/
public class ContinuousTestGeneration {
/**
* Target folder/jar defining the SUT
*/
private final String target;
/**
* Defines what classes in the target should be used by specifying
* a common package prefix
*/
private final String prefix;
/**
* The complete, used classpath
*/
private final String projectClassPath;
private CtgConfiguration configuration;
/**
* An optional folder where to make a copy of the generated tests
*/
private final String exportFolder;
/**
* Specify which CUT to use. If {@code null} then use everything in target/prefix
*/
private String[] cuts;
public ContinuousTestGeneration(String target, String projectClassPath, String prefix, CtgConfiguration conf, String[] cuts,
String exportFolder) {
super();
this.target = target;
this.prefix = prefix;
this.projectClassPath = projectClassPath;
this.configuration = conf;
this.cuts = cuts;
this.exportFolder = exportFolder;
}
/**
* Apply CTG, and return a string with some summary
*
* @return
*/
public String execute() {
//init the local storage manager
StorageManager storage = new StorageManager();
if (!storage.isStorageOk()) {
return "Failed to initialize local storage system";
}
if(Properties.CTG_DELETE_OLD_TMP_FOLDERS){
storage.deleteAllOldTmpFolders();
}
if (!storage.createNewTmpFolders()) {
return "Failed to create tmp folders";
}
//check project
ProjectAnalyzer analyzer = new ProjectAnalyzer(target, prefix, cuts);
ProjectStaticData data = analyzer.analyze();
if (data.getTotalNumberOfTestableCUTs() == 0) {
return "There is no class to test in the chosen project\n" +
"Target: " + target + "\n" +
"Prefix: '" + prefix + "'\n";
}
if(Properties.CTG_DEBUG_PORT != null && data.getTotalNumberOfTestableCUTs() != 1){
throw new IllegalStateException("Cannot debug CTG when more than one CUT is selected");
}
if (Properties.CTG_TIME_PER_CLASS != null) {
configuration = configuration.getWithChangedTime(Properties.CTG_TIME_PER_CLASS, data.getTotalNumberOfTestableCUTs());
}
JobScheduler scheduler = new JobScheduler(data, configuration);
JobExecutor executor = new JobExecutor(storage, projectClassPath, configuration);
//loop: define (partial) schedule
while (scheduler.canExecuteMore()) {
List jobs = scheduler.createNewSchedule();
executor.executeJobs(jobs, configuration.getNumberOfUsableCores());
executor.waitForJobs();
}
String description = storage.mergeAndCommitChanges(data, cuts);
if(exportFolder != null){
try {
exportToFolder(".",exportFolder);
} catch (IOException e) {
return "Failed to export tests: "+e.getMessage();
}
}
//call home
if (configuration.callHome) {
//TODO
}
return description;
}
public static File resolveExportFolder(String baseFolder, String exportFolder){
Path exp = Paths.get(exportFolder);
if(exp.isAbsolute()){
return exp.toFile();
} else {
return Paths.get(baseFolder,exportFolder).toAbsolutePath().toFile();
}
}
public static boolean exportToFolder(String baseFolder, String exportFolder) throws IOException {
File basedir = new File(baseFolder);
File evoFolder = StorageManager.getBestTestFolder(basedir);
File[] children = evoFolder.listFiles();
boolean isEmpty = children==null || children.length==0;
if(isEmpty){
return false;
}
File target = resolveExportFolder(baseFolder, exportFolder);
//FileUtils.copyDirectory(evoFolder, target); //This did not overwrite old files!
FileIOUtils.copyDirectoryAndOverwriteFilesIfNeeded(evoFolder,target);
return true;
}
/**
* Clean all persistent data (eg files on disk) that
* CTG has created so far
*/
public boolean clean(){
StorageManager storage = new StorageManager();
return storage.clean();
}
/**
* Get info on the current test cases in the database
* @return
*/
public String info(){
Project project = StorageManager.getDatabaseProject();
if(project==null){
return "No info available";
}
//TODO all info
StringBuilder sb = new StringBuilder();
sb.append("Total number of classes in the project: "+
ProjectUtil.getNumberTestableClasses(project)+"\n");
sb.append("Number of classes in the project that are testable: "+
ProjectUtil.getNumberTestableClasses(project)+"\n");
sb.append("Number of generated test suites: "+
ProjectUtil.getNumberGeneratedTestSuites(project)+"\n");
sb.append("Overall coverage: "+
ProjectUtil.getOverallCoverage(project)+"\n");
return sb.toString();
}
}