/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI 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 General Public License for more details at gnu.org.
*/
package com.eviware.soapui.tools;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlRunTestCaseTestStep;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.model.iface.MessageExchange;
import com.eviware.soapui.model.project.ProjectFactoryRegistry;
import com.eviware.soapui.model.security.SecurityScan;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestStepResult;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.report.JUnitSecurityReportCollector;
import com.eviware.soapui.security.SecurityTest;
import com.eviware.soapui.security.SecurityTestRunContext;
import com.eviware.soapui.security.SecurityTestRunner;
import com.eviware.soapui.security.result.SecurityResult;
import com.eviware.soapui.security.result.SecurityScanRequestResult;
import com.eviware.soapui.security.result.SecurityScanResult;
import com.eviware.soapui.security.result.SecurityTestStepResult;
import com.eviware.soapui.security.result.SecurityResult.ResultStatus;
import com.eviware.soapui.security.support.SecurityTestRunListener;
import com.eviware.soapui.security.support.SecurityTestRunListenerAdapter;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.Tools;
/**
* Standalone security test-runner used from maven-plugin, can also be used from
* command-line (see xdocs) or directly from other classes.
* <p>
* For standalone usage, set the project file (with setProjectFile) and other
* desired properties before calling run
* </p>
*
* @author nebojsa.tasic
*/
public class SoapUISecurityTestRunner extends SoapUITestCaseRunner implements SecurityTestRunListener
{
public static final String SOAPUI_EXPORT_SEPARATOR = "soapui.export.separator";
public static final String TITLE = "soapUI " + SoapUI.SOAPUI_VERSION + " Security Test Runner";
private String securityTestName;
private int securityTestCount;
private int securityScanCount;
private int securityScanRequestCount;
private int securityScanAlertCount;
private List<SecurityTestStepResult> failedResults = new ArrayList<SecurityTestStepResult>();
private JUnitSecurityReportCollector reportCollector = new JUnitSecurityReportCollector();
/**
* Runs the tests in the specified soapUI project file, see soapUI xdocs for
* details.
*
* @param args
* @throws Exception
*/
public static void main( String[] args ) throws Exception
{
System.exit( new SoapUISecurityTestRunner().runFromCommandLine( args ) );
}
protected boolean processCommandLine( CommandLine cmd )
{
if( cmd.hasOption( "n" ) )
setSecurityTestName( cmd.getOptionValue( "n" ) );
return super.processCommandLine( cmd );
}
public void setSecurityTestName( String securityTestName )
{
this.securityTestName = securityTestName;
}
protected SoapUIOptions initCommandLineOptions()
{
SoapUIOptions options = super.initCommandLineOptions();
options.addOption( "n", true, "Sets the security test name" );
return options;
}
public SoapUISecurityTestRunner()
{
super( SoapUISecurityTestRunner.TITLE );
}
public SoapUISecurityTestRunner( String title )
{
super( title );
}
public boolean runRunner() throws Exception
{
initGroovyLog();
getAssertions().clear();
String projectFile = getProjectFile();
WsdlProject project = ( WsdlProject )ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( projectFile,
getProjectPassword() );
if( project.isDisabled() )
throw new Exception( "Failed to load soapUI project file [" + projectFile + "]" );
initProject( project );
ensureOutputFolder( project );
log.info( "Running soapUI tests in project [" + project.getName() + "]" );
String testSuite = getTestSuite();
String testCase = getTestCase();
long startTime = System.nanoTime();
List<TestCase> testCasesToRun = new ArrayList<TestCase>();
// start by listening to all testcases.. (since one testcase can call
// another)
for( int c = 0; c < project.getTestSuiteCount(); c++ )
{
TestSuite suite = project.getTestSuiteAt( c );
for( int i = 0; i < suite.getTestCaseCount(); i++ )
{
TestCase tc = suite.getTestCaseAt( i );
if( ( testSuite == null || suite.getName().equals( suite.getName() ) ) && testCase != null
&& tc.getName().equals( testCase ) )
testCasesToRun.add( tc );
addListeners( tc );
}
}
// decide what to run
if( testCasesToRun.size() > 0 )
{
for( TestCase tc : testCasesToRun )
{
runTestCase( ( WsdlTestCase )tc );
}
}
else if( testSuite != null )
{
WsdlTestSuite ts = project.getTestSuiteByName( testSuite );
if( ts == null )
throw new Exception( "TestSuite with name [" + testSuite + "] not found in project" );
else
runSuite( ts );
}
else
{
runProject( project );
}
long timeTaken = ( System.nanoTime() - startTime ) / 1000000;
if( isPrintReport() )
{
printReport( timeTaken );
}
exportReports( project );
if( isSaveAfterRun() && !project.isRemote() )
{
try
{
project.save();
}
catch( Throwable t )
{
log.error( "Failed to save project", t );
}
}
if( securityScanAlertCount > 0 && !isIgnoreErrors() )
{
throw new Exception( "SecurityTest execution failed with " + securityScanAlertCount + " alert"
+ ( securityScanAlertCount > 1 ? "s" : "" ) );
}
return true;
}
protected void runProject( WsdlProject project )
{
try
{
log.info( ( "Running Project [" + project.getName() + "], runType = " + project.getRunType() ) );
for( TestSuite testSuite : project.getTestSuiteList() )
{
runSuite( ( WsdlTestSuite )testSuite );
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
protected void initProject( WsdlProject project ) throws Exception
{
initProjectProperties( project );
}
protected void exportReports( WsdlProject project ) throws Exception
{
if( isJUnitReport() )
{
exportJUnitReports( reportCollector, getAbsoluteOutputFolder( project ), project );
}
}
protected void addListeners( TestCase tc )
{
tc.addTestRunListener( this );
if( isJunitReport() )
tc.addTestRunListener( reportCollector );
}
public void exportJUnitReports( JUnitSecurityReportCollector collector, String folder, WsdlProject project )
throws Exception
{
collector.saveReports( folder == null ? "" : folder );
}
public void printReport( long timeTaken )
{
System.out.println();
System.out.println( "SoapUI " + SoapUI.SOAPUI_VERSION + " Security TestCaseRunner Summary" );
System.out.println( "-----------------------------" );
System.out.println( "Time Taken: " + timeTaken + "ms" );
System.out.println( "Total SecurityTests: " + securityTestCount );
System.out.println( "Total SecurityScans: " + securityScanCount );
System.out.println( "Total SecurityScan Requests: " + securityScanRequestCount );
System.out.println( "Total Failed SecurityScan Requests: " + securityScanAlertCount );
}
/**
* Run tests in the specified TestSuite
*
* @param suite
* the TestSuite to run
*/
protected void runSuite( WsdlTestSuite suite )
{
try
{
for( TestCase testCase : suite.getTestCaseList() )
{
runTestCase( ( WsdlTestCase )testCase );
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
/**
* Runs the SecurityTests in the specified TestCase
*
* @param testCase
* the testcase to run
* @param context
*/
protected void runTestCase( WsdlTestCase testCase )
{
try
{
for( SecurityTest securityTest : testCase.getSecurityTestList() )
{
securityTest.addSecurityTestRunListener( this );
if( StringUtils.isNullOrEmpty( securityTestName ) || securityTest.getName().equals( securityTestName ) )
runSecurityTest( securityTest );
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
/**
* @param securityTest
*/
protected void runSecurityTest( SecurityTest securityTest )
{
securityTest.addSecurityTestRunListener( new SecurityTestRunListenerAdapter()
{
private int requestIndex = 0;
@Override
public void afterSecurityScanRequest( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScanRequestResult securityCheckReqResult )
{
securityScanRequestCount++ ;
if( securityCheckReqResult.getStatus() == ResultStatus.FAILED )
{
securityScanAlertCount++ ;
}
log.info( securityCheckReqResult.getSecurityScan().getName() + " - "
+ securityCheckReqResult.getChangedParamsInfo( ++requestIndex ) );
}
@Override
public void afterSecurityScan( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScanResult securityCheckResult )
{
securityScanCount++ ;
}
@Override
public void beforeSecurityScan( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScan securityCheck )
{
requestIndex = 0;
}
@Override
public void afterStep( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityTestStepResult result )
{
if( result.getStatus() == ResultStatus.FAILED )
failedResults.add( result );
}
} );
if( isJUnitReport() )
securityTest.addSecurityTestRunListener( reportCollector );
log.info( "Running SecurityTest [" + securityTest.getName() + "] in TestCase ["
+ securityTest.getTestCase().getName() + "] in TestSuite ["
+ securityTest.getTestCase().getTestSuite().getName() + "]" );
SecurityTestRunner runner = securityTest.run( null, false );
// log.info( "\n" + securityTest.getSecurityTestLog().getMessages() );
log.info( "SecurityTest [" + securityTest.getName() + "] finished with status [" + runner.getStatus() + "] in "
+ ( runner.getTimeTaken() ) + "ms" );
if( isJUnitReport() )
securityTest.removeSecurityTestRunListener( reportCollector );
}
public void beforeRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
{
}
public void beforeStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStep currentStep )
{
}
public void afterStep( TestCaseRunner testRunner, TestCaseRunContext runContext, TestStepResult result )
{
}
@Override
public void afterStep( TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityTestStepResult result )
{
if( !isPrintReport() )
return;
TestStep currentStep = runContext.getCurrentStep();
String securityTestName = "";
String securityScanName = "";
if( !result.getSecurityScanResultList().isEmpty() )
{
securityTestName = result.getSecurityScanResultList().get( 0 ).getSecurityScan().getParent().getName();
securityScanName = result.getSecurityScanResultList().get( 0 ).getSecurityScanName();
}
String countPropertyName = currentStep.getName() + " run count";
Long count = new Long( getExportCount() );// ( Long
// )runContext.getProperty(
// countPropertyName );
if( count == null )
{
count = new Long( 0 );
}
runContext.setProperty( countPropertyName, new Long( count.longValue() + 1 ) );
if( result.getStatus() == SecurityResult.ResultStatus.FAILED || isExportAll() )
{
try
{
String exportSeparator = System.getProperty( SOAPUI_EXPORT_SEPARATOR, "-" );
TestCase tc = currentStep.getTestCase();
String nameBase = StringUtils.createFileName( securityTestName, '_' ) + exportSeparator
+ StringUtils.createFileName( securityScanName, '_' ) + exportSeparator
+ StringUtils.createFileName( tc.getTestSuite().getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( tc.getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( currentStep.getName(), '_' ) + "-" + count.longValue() + "-"
+ result.getStatus();
WsdlTestCaseRunner callingTestCaseRunner = ( WsdlTestCaseRunner )runContext
.getProperty( "#CallingTestCaseRunner#" );
if( callingTestCaseRunner != null )
{
WsdlTestCase ctc = callingTestCaseRunner.getTestCase();
WsdlRunTestCaseTestStep runTestCaseTestStep = ( WsdlRunTestCaseTestStep )runContext
.getProperty( "#CallingRunTestCaseStep#" );
nameBase = StringUtils.createFileName( securityTestName, '_' ) + exportSeparator
+ StringUtils.createFileName( ctc.getTestSuite().getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( ctc.getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( runTestCaseTestStep.getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( tc.getTestSuite().getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( tc.getName(), '_' ) + exportSeparator
+ StringUtils.createFileName( currentStep.getName(), '_' ) + "-" + count.longValue() + "-"
+ result.getStatus();
}
String absoluteOutputFolder = getAbsoluteOutputFolder( ModelSupport.getModelItemProject( tc ) );
String fileName = absoluteOutputFolder + File.separator + nameBase + ".txt";
if( result.getStatus() == SecurityResult.ResultStatus.FAILED )
log.error( currentStep.getName() + " failed, exporting to [" + fileName + "]" );
new File( fileName ).getParentFile().mkdirs();
PrintWriter writer = new PrintWriter( fileName );
result.writeTo( writer );
writer.close();
// write attachments
if( result instanceof MessageExchange )
{
Attachment[] attachments = ( ( MessageExchange )result ).getResponseAttachments();
if( attachments != null && attachments.length > 0 )
{
for( int c = 0; c < attachments.length; c++ )
{
fileName = nameBase + "-attachment-" + ( c + 1 ) + ".";
Attachment attachment = attachments[c];
String contentType = attachment.getContentType();
if( !"application/octet-stream".equals( contentType ) && contentType != null
&& contentType.indexOf( '/' ) != -1 )
{
fileName += contentType.substring( contentType.lastIndexOf( '/' ) + 1 );
}
else
{
fileName += "dat";
}
fileName = absoluteOutputFolder + File.separator + fileName;
FileOutputStream outFile = new FileOutputStream( fileName );
Tools.writeAll( outFile, attachment.getInputStream() );
outFile.close();
}
}
}
setExportCount( getExportCount() + 1 );
}
catch( Exception e )
{
log.error( "Error saving failed result: " + e, e );
}
}
setTestStepCount( getTestStepCount() + 1 );
}
public void afterRun( TestCaseRunner testRunner, TestCaseRunContext runContext )
{
}
@Override
public void afterOriginalStep( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityTestStepResult result )
{
// TODO Auto-generated method stub
}
@Override
public void afterRun( TestCaseRunner testRunner, SecurityTestRunContext runContext )
{
// TODO Auto-generated method stub
}
@Override
public void afterSecurityScan( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScanResult securityScanResult )
{
// TODO Auto-generated method stub
}
@Override
public void afterSecurityScanRequest( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScanRequestResult securityScanReqResult )
{
// TODO Auto-generated method stub
}
@Override
public void beforeRun( TestCaseRunner testRunner, SecurityTestRunContext runContext )
{
// TODO Auto-generated method stub
}
@Override
public void beforeSecurityScan( TestCaseRunner testRunner, SecurityTestRunContext runContext,
SecurityScan securityScan )
{
// TODO Auto-generated method stub
}
@Override
public void beforeStep( TestCaseRunner testRunner, SecurityTestRunContext runContext, TestStepResult testStepResult )
{
// TODO Auto-generated method stub
}
}