/*
* Copyright (C) 2008 Digital Sundhed (SDSD)
*
* All source code and information supplied as part of chronos
* is copyright to its contributers.
*
* The source code has been released under a dual license - meaning you can
* use either licensed version of the library with your code.
*
* It is released under the Common Public License 1.0, a copy of which can
* be found at the link below.
* http://www.opensource.org/licenses/cpl.php
*
* It is released under the LGPL (GNU Lesser General Public License), either
* version 2.1 of the License, or (at your option) any later version. A copy
* of which can be found at the link below.
* http://www.gnu.org/copyleft/lesser.html
*/
package org.codehaus.mojo.chronos.jmeter;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.chronos.Utils;
import org.codehaus.mojo.chronos.gc.GCLogParser;
import org.codehaus.mojo.chronos.gc.GCSamples;
import org.codehaus.mojo.chronos.responsetime.ResponsetimeSamples;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.xml.sax.SAXException;
/**
* Invokes JMeter.<br />
* JMeter is invoked by spawning a separate process to make it possible to control startup parameters. Can also be used
* by specifying a .jtl file as input and (possibly) a garbage collection logfile.
*
* @author ksr@lakeside.dk
* @goal jmeter
* @phase integration-test
*/
public class JMeterTestMojo extends JMeterMojo {
/**
* The current maven project.
*
* @parameter expression="${project}"
*/
protected MavenProject project;
/**
* The inputfile. This could either be a .jtl file or a .jmx file. In the latter case, jmeter is invoked, and the
* generated .jtl file parsed afterwards.
*
* @parameter
* @required
*/
private File input;
/**
* The id of the jmeter invocation.
*
* @parameter default-value="performancetest"
*/
private String dataid;
/**
* Will garbage collections be logged? Note that this is really only relevant if your tests are junitsamples in
* jmeter.
*
* @parameter default-value=true
*/
private boolean loggc;
/**
* The name of an (optional) garbage collection logfile. Only used when loggc is set to true.
*
* @parameter
*/
private File gclogfile;
/**
* Clasname of an (optional) bootstrapperclass. The purpose is to allow bootstrapping the proces eg. by initializing
* testdata in a relational database without measuring the time.
*
* @parameter
*/
private String bootstrapper;
public void execute() throws MojoExecutionException {
ensureJMeter();
if(!input.exists()) {
throw new MojoExecutionException("Invalid argument 'input', file " + input.getPath() + " does notexist.");
}
if(getJtlFile().exists() && input.lastModified() > getJtlFile().lastModified()) {
getLog().info("clearing old testlog");
getJtlFile().delete();
}
if(!getJtlFile().exists()) {
if(bootstrapper != null) {
getLog().info("Launching bootstrapper " + bootstrapper);
JavaCommand bootstrapCmd = new JavaCommand(project.getBasedir().getAbsolutePath(), getLog());
bootstrapCmd.addArgument("-cp");
StringBuffer classPath = new StringBuffer();
Iterator it = getDependencyUtil().getDependencies(project).iterator();
while (it.hasNext()) {
Artifact artifact = (Artifact)it.next();
classPath.append(artifact.getFile());
if(it.hasNext()) {
classPath.append(File.pathSeparatorChar);
}
}
bootstrapCmd.addArgument(classPath.toString());
bootstrapCmd.addArgument(bootstrapper);
try {
int result = bootstrapCmd.execute();
if(result != 0) {
throw new MojoExecutionException("Result of " + bootstrapCmd + " execution is: '" + result
+ "'.");
}
} catch (CommandLineException e) {
throw new MojoExecutionException("Could not create bootstrapper", e);
}
} else {
getLog().info("No bootstrapper class found");
}
JavaCommand java = getJavaLauncher();
java.addArgument("-jar");
String jmeterJar = getJmeterJar().getAbsolutePath();
java.addArgument(jmeterJar);
// non-gui
java.addArgument("-n");
// testplan inside this file
java.addArgument("-t");
java.addArgument(input.getAbsolutePath());
// output jtl
java.addArgument("-l");
java.addArgument(getJtlFile().getAbsolutePath());
getLog().info("Excuting test " + input.getPath());
executeJmeter(java);
} else {
getLog().info("jtl file " + getJtlFile().getAbsolutePath() + " up-to-date, skipping...");
}
if(loggc && getGcLogFile().exists()) {
parseGCLog();
}
parseJmeterLog();
}
public void setInput(File input) {
this.input = input;
}
public void setDataid(String dataid) {
this.dataid = dataid;
}
public void setLoggc(boolean loggc) {
this.loggc = loggc;
}
public void setGclogfile(File gclogfile) {
this.gclogfile = gclogfile;
}
private void parseGCLog() throws MojoExecutionException {
try {
GCSamples samples = new GCLogParser().parseGCLog(getGcLogFile());
Utils.writeObject(samples, Utils.getGcSamplesSer(getProject().getBasedir(), dataid));
} catch (IOException e) {
throw new MojoExecutionException("Unable to parse garbage collection log", e);
}
}
private void parseJmeterLog() throws MojoExecutionException {
File perfSamplesSer = Utils.getPerformanceSamplesSer(getProject().getBasedir(), dataid);
try {
ResponsetimeSamples samples = new JMeterLogParser().parseJMeterLog(getJtlFile());
Utils.writeObject(samples, perfSamplesSer);
} catch (IOException e) {
throw new MojoExecutionException("Could not parse jmeter log", e);
} catch (SAXException e) {
throw new MojoExecutionException("Could not parse jmeter log", e);
}
}
private File getJtlFile() {
if(input.getName().endsWith(".jtl")) {
return input;
}
File chronosDir = Utils.getChronosDir(getProject().getBasedir());
return new File(chronosDir, "jmeterlog-" + dataid + ".jtl");
}
protected final File getGcLogFile() {
if(!loggc) {
return null;
}
if(gclogfile != null) {
return gclogfile;
}
File chronosDir = Utils.getChronosDir(getProject().getBasedir());
return new File(chronosDir, "gclog-" + dataid + ".txt");
}
protected final MavenProject getProject() {
return project;
}
}