/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.tools;
import com.eviware.soapui.DefaultSoapUICore;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.SoapUICore;
import com.eviware.soapui.SoapUIExtensionClassLoader;
import com.eviware.soapui.SoapUIExtensionClassLoader.SoapUIClassLoaderState;
import com.eviware.soapui.StandaloneSoapUICore;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.submit.filters.GlobalHttpHeadersRequestFilter;
import com.eviware.soapui.impl.wsdl.support.PathUtils;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.project.Project;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import java.io.File;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class AbstractSoapUIRunner implements CmdLineRunner {
public static final int NORMAL_TERMINATION = 0;
public static final int ABNORMAL_TERMINATION = -1;
private boolean groovyLogInitialized;
private String projectFile;
protected final Logger log = Logger.getLogger(getClass());
private String settingsFile;
private String soapUISettingsPassword;
private String projectPassword;
private boolean enableUI;
private String outputFolder;
private String[] projectProperties;
private Map<String, String> runnerGlobalProperties = new HashMap<String, String>();
public AbstractSoapUIRunner(String title) {
if (title != null) {
System.out.println(title);
}
SoapUI.setCmdLineRunner(this);
}
protected void initGroovyLog() {
if (!groovyLogInitialized) {
ensureConsoleAppenderIsDefined(Logger.getLogger("groovy.log"));
groovyLogInitialized = true;
}
}
/**
* Ensure there is one (and only one) ConsoleAppender instance configured for <code>logger</code>.
*
* @param logger
*/
protected void ensureConsoleAppenderIsDefined(Logger logger) {
if (logger != null) {
// ensure there is a ConsoleAppender defined, adding one if necessary
for (Object appender : Collections.list(logger.getAllAppenders())) {
if (appender instanceof ConsoleAppender) {
return;
}
}
ConsoleAppender consoleAppender = new ConsoleAppender();
consoleAppender.setWriter(new OutputStreamWriter(System.out));
consoleAppender.setLayout(new PatternLayout("%d{ABSOLUTE} %-5p [%c{1}] %m%n"));
logger.addAppender(consoleAppender);
}
}
/**
* Validates the command line arguments and runs the test runner if vaild
*
* @param args the commandline arguments to the runner
* @return status code to be used with System.exit()
* @see java.lang.System
*/
public int runFromCommandLine(String[] args) {
int results = ABNORMAL_TERMINATION;
if (validateCommandLineArgument(args)) {
results = run(args);
}
return results;
}
public boolean validateCommandLineArgument(String[] args) {
boolean commandLineArgumentsAreValid = false;
try {
commandLineArgumentsAreValid = initFromCommandLine(args, true);
} catch (Exception e) {
log.error(e);
SoapUI.logError(e);
}
return commandLineArgumentsAreValid;
}
/**
* Runs the testrunner
*
* @param args the command line arguments to be passed to the testrunner
* @return status code to be used with System.exit()
* @see java.lang.System
*/
public int run(String[] args) {
try {
if (run()) {
return NORMAL_TERMINATION;
}
} catch (Exception e) {
log.error(e);
SoapUI.logError(e);
}
return ABNORMAL_TERMINATION;
}
public boolean initFromCommandLine(String[] args, boolean printHelp) throws Exception {
SoapUIOptions options = initCommandLineOptions();
CommandLineParser parser = new PosixParser();
CommandLine cmd = parser.parse(options, args);
if (requiresProjectArgument(cmd)) {
args = cmd.getArgs();
if (args.length != 1) {
if (printHelp) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(options.getRunnerName() + " [options] <soapui-project-file>", options);
}
System.err.println("Missing SoapUI project file..");
return false;
}
setProjectFile(args[0]);
}
return processCommandLine(cmd);
}
/**
* Checks if the command line arguments require a project file
* @param cmd The command line
* @return true as default
*/
protected boolean requiresProjectArgument(CommandLine cmd) {
return true;
}
/**
* Main method to use for running the configured tests. Call after setting
* properties, etc as desired.
*
* @return true if execution should be blocked
* @throws Exception if an error or failure occurs during test execution
*/
public final boolean run() throws Exception {
if (SoapUI.getSoapUICore() == null) {
SoapUI.setSoapUICore(createSoapUICore(), true);
SoapUI.initGCTimer();
}
for (String name : runnerGlobalProperties.keySet()) {
PropertyExpansionUtils.getGlobalProperties().setPropertyValue(name, runnerGlobalProperties.get(name));
}
SoapUIClassLoaderState state = SoapUIExtensionClassLoader.ensure();
try {
return runRunner();
} finally {
state.restore();
}
}
protected SoapUICore createSoapUICore() {
if (enableUI) {
StandaloneSoapUICore core = new StandaloneSoapUICore(settingsFile);
log.info("Enabling UI Components");
core.prepareUI();
UISupport.setMainFrame(null);
return core;
} else {
return new DefaultSoapUICore(null, settingsFile, soapUISettingsPassword);
}
}
protected abstract boolean processCommandLine(CommandLine cmd);
protected abstract SoapUIOptions initCommandLineOptions();
protected abstract boolean runRunner() throws Exception;
protected String getCommandLineOptionSubstSpace(CommandLine cmd, String key) {
return cmd.getOptionValue(key).replaceAll("%20", " ");
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.tools.CmdLineRunner#getProjectFile()
*/
@Override
public String getProjectFile() {
return projectFile;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.tools.CmdLineRunner#getSettingsFile()
*/
@Override
public String getSettingsFile() {
return settingsFile;
}
public void setOutputFolder(String outputFolder) {
this.outputFolder = outputFolder;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.tools.CmdLineRunner#getOutputFolder()
*/
@Override
public String getOutputFolder() {
return this.outputFolder;
}
public String getAbsoluteOutputFolder(ModelItem modelItem) {
String folder = PropertyExpander.expandProperties(modelItem, outputFolder);
if (StringUtils.isNullOrEmpty(folder)) {
folder = PathUtils.getExpandedResourceRoot(modelItem);
} else if (PathUtils.isRelativePath(folder)) {
folder = PathUtils.resolveResourcePath(folder, modelItem);
}
return folder;
}
public String getModelItemOutputFolder(ModelItem modelItem) {
List<ModelItem> chain = new ArrayList<ModelItem>();
ModelItem p = modelItem;
while (!(p instanceof Project)) {
chain.add(0, p);
p = p.getParent();
}
File dir = new File(getAbsoluteOutputFolder(modelItem));
dir.mkdir();
for (ModelItem item : chain) {
dir = new File(dir, StringUtils.createFileName(item.getName(), '-'));
dir.mkdir();
}
return dir.getAbsolutePath();
}
protected void ensureOutputFolder(ModelItem modelItem) {
ensureFolder(getAbsoluteOutputFolder(modelItem));
}
public void ensureFolder(String path) {
if (path == null) {
return;
}
File folder = new File(path);
if (!folder.exists() || !folder.isDirectory()) {
folder.mkdirs();
}
}
/**
* Sets the SoapUI project file containing the tests to run
*
* @param projectFile the SoapUI project file containing the tests to run
*/
public void setProjectFile(String projectFile) {
this.projectFile = projectFile;
}
/**
* Sets the SoapUI settings file containing the tests to run
*
* @param settingsFile the SoapUI settings file to use
*/
public void setSettingsFile(String settingsFile) {
this.settingsFile = settingsFile;
}
public void setEnableUI(boolean enableUI) {
this.enableUI = enableUI;
}
public static class SoapUIOptions extends Options {
private final String runnerName;
public SoapUIOptions(String runnerName) {
this.runnerName = runnerName;
}
public String getRunnerName() {
return runnerName;
}
}
public String getSoapUISettingsPassword() {
return soapUISettingsPassword;
}
public void setSoapUISettingsPassword(String soapUISettingsPassword) {
this.soapUISettingsPassword = soapUISettingsPassword;
}
public void setSystemProperties(String[] optionValues) {
for (String option : optionValues) {
int ix = option.indexOf('=');
if (ix != -1) {
System.setProperty(option.substring(0, ix), option.substring(ix + 1));
}
}
}
public void setCustomHeaders( String[] optionValues )
{
for( String option : optionValues )
{
int ix = option.indexOf( '=' );
if( ix != -1 )
{
// not optimal - it would be nicer if the filter could access command-line options via some
// generic mechanism.
String name = option.substring(0, ix);
String value = option.substring(ix + 1);
log.info( "Adding global HTTP Header [" + name + "] = [" + value + "]");
GlobalHttpHeadersRequestFilter.addGlobalHeader(name, value);
}
}
}
public void setGlobalProperties(String[] optionValues) {
for (String option : optionValues) {
int ix = option.indexOf('=');
if (ix != -1) {
String name = option.substring(0, ix);
String value = option.substring(ix + 1);
log.info("Setting global property [" + name + "] to [" + value + "]");
// PropertyExpansionUtils.getGlobalProperties().setPropertyValue( name, value );
runnerGlobalProperties.put(name, value);
}
}
}
public void setProjectProperties(String[] projectProperties) {
this.projectProperties = projectProperties;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.tools.CmdLineRunner#getLog()
*/
@Override
public Logger getLog() {
return log;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.tools.CmdLineRunner#getProjectProperties()
*/
@Override
public String[] getProjectProperties() {
return projectProperties;
}
protected void initProjectProperties(WsdlProject project) {
if (projectProperties != null) {
for (String option : projectProperties) {
int ix = option.indexOf('=');
if (ix != -1) {
String name = option.substring(0, ix);
String value = option.substring(ix + 1);
log.info("Setting project property [" + name + "] to [" + value + "]");
project.setPropertyValue(name, value);
}
}
}
}
public boolean isEnableUI() {
return enableUI;
}
public String getProjectPassword() {
return projectPassword;
}
public void setProjectPassword(String projectPassword) {
this.projectPassword = projectPassword;
}
}