/*
* Copyright (c) 2007, Ounce Labs, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY OUNCE LABS, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL OUNCE LABS, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.mojo.ounce.its;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import junit.framework.AssertionFailedError;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.invoker.InvocationRequest;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.test.plugin.BuildTool;
import org.apache.maven.shared.test.plugin.PluginTestTool;
import org.apache.maven.shared.test.plugin.ProjectTool;
import org.apache.maven.shared.test.plugin.TestToolsException;
import org.codehaus.classworlds.ClassRealm;
import org.codehaus.mojo.ounce.utils.Utils;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
/**
* @author <a href="mailto:brianf@apache.org">Brian Fox</a> Copied from the Eclipse AbstractEclipsePluginTestCase v2.4
* @version $Id$
*/
public abstract class AbstractOuncePluginITCase
extends PlexusTestCase
{
private BuildTool buildTool;
private ProjectTool projectTool;
/**
* Test repository directory.
*/
protected static File localRepositoryDirectory = getTestFile( "target/test-classes/m2repo" );
/**
* Pom File
*/
protected static File PomFile = new File( getBasedir(), "pom.xml" );
/**
* Group-Id for running test builds.
*/
protected static final String GROUP_ID = "org.codehaus.mojo";
/**
* Artifact-Id for running test builds.
*/
protected static final String ARTIFACT_ID = "ounce-maven-plugin";
/**
* Version under which the plugin was installed to the test-time local repository for running test builds.
*/
protected static final String VERSION = "test";
private static final String BUILD_OUTPUT_DIRECTORY = "target/surefire-reports/build-output";
private static boolean installed = false;
Properties props = new Properties();
/**
* @see org.codehaus.plexus.PlexusTestCase#setUp()
*/
protected void setUp()
throws Exception
{
if ( !installed )
{
System.out.println( "*** Running integation test builds; output will be directed to: " +
BUILD_OUTPUT_DIRECTORY + "\n" );
}
props.setProperty( "ounce.core", "test-xml" );
super.setUp();
buildTool = (BuildTool) lookup( BuildTool.ROLE, "default" );
projectTool = (ProjectTool) lookup( ProjectTool.ROLE, "default" );
String mavenHome = System.getProperty( "maven.home" );
// maven.home is set by surefire when the test is
// run with maven, but better make the test run in
// IDEs without
// the need of additional properties
if ( mavenHome == null )
{
String path = System.getProperty( "java.library.path" );
String[] paths = StringUtils.split( path, System.getProperty( "path.separator" ) );
for ( int j = 0; j < paths.length; j++ )
{
String pt = paths[j];
if ( new File( pt, "mvn" ).exists() )
{
System.setProperty( "maven.home", new File( pt ).getAbsoluteFile().getParent() );
break;
}
}
}
System.setProperty( "MAVEN_TERMINATE_CMD", "on" );
synchronized ( AbstractOuncePluginITCase.class )
{
if ( !installed )
{
PluginTestTool pluginTestTool = (PluginTestTool) lookup( PluginTestTool.ROLE, "default" );
localRepositoryDirectory =
pluginTestTool.preparePluginForUnitTestingWithMavenBuilds( PomFile, "test",
localRepositoryDirectory );
System.out.println( "*** Installed test-version of the Ounce plugin to: " + localRepositoryDirectory +
"\n" );
installed = true;
}
}
}
/**
* @see org.codehaus.plexus.PlexusTestCase#tearDown()
*/
protected void tearDown()
throws Exception
{
super.tearDown();
List containers = new ArrayList();
containers.add( getContainer() );
for ( Iterator iter = containers.iterator(); iter.hasNext(); )
{
PlexusContainer container = (PlexusContainer) iter.next();
if ( container != null )
{
container.dispose();
ClassRealm realm = container.getContainerRealm();
if ( realm != null )
{
realm.getWorld().disposeRealm( realm.getId() );
}
}
}
}
/**
* Execute the plugin with no properties
*
* @param projectName project directory
* @param goalList comma separated list of goals to execute
* @throws Exception any exception generated during test
*/
protected void testProject( String projectName, String goalList )
throws Exception
{
Properties props = new Properties();
testProject( projectName, props, goalList );
}
/**
* Execute the plugin.
*
* @param projectName project directory
* @param properties additional properties
* @param goalList comma separated list of goals to execute
* @throws Exception any exception generated during test
*/
protected void testProject( String projectName, Properties properties, String goalList )
throws Exception
{
System.out.println( "Executing Test Project: " + projectName + "..." );
File theBasedir = getTestFile( "target/test-classes/its/" + projectName );
File pom = new File( theBasedir, "pom.xml" );
String[] goal = goalList.split( "," );
List goals = new ArrayList();
for ( int i = 0; i < goal.length; i++ )
{
goals.add( goal[i] );
}
executeMaven( pom, properties, goals );
MavenProject project = readProject( pom );
File testOutDir = new File( project.getBuild().getDirectory() );
compareDirectoryContent( theBasedir, testOutDir, "" );
System.out.println( "Success!" );
}
protected File getOutputDirectory( String projectName )
{
return getTestFile( "target/test-classes/projects/" + projectName );
}
protected void executeMaven( File pom, Properties properties, List goals )
throws TestToolsException, ExecutionFailedException
{
executeMaven( pom, properties, goals, true );
}
protected void executeMaven( File pom, Properties properties, List goals, boolean switchLocalRepo )
throws TestToolsException, ExecutionFailedException
{
// insert the test property to activate the test
// profile
properties.setProperty( "test", "true" );
new File( BUILD_OUTPUT_DIRECTORY ).mkdirs();
NullPointerException npe = new NullPointerException();
StackTraceElement[] trace = npe.getStackTrace();
File buildLog = null;
for ( int i = 0; i < trace.length; i++ )
{
StackTraceElement element = trace[i];
String methodName = element.getMethodName();
if ( methodName.startsWith( "test" ) && !methodName.equals( "testProject" ) )
{
String classname = element.getClassName();
buildLog = new File( BUILD_OUTPUT_DIRECTORY, classname + "_" + element.getMethodName() + ".build.log" );
break;
}
}
if ( buildLog == null )
{
buildLog = new File( BUILD_OUTPUT_DIRECTORY, "unknown.build.log" );
}
InvocationRequest request = buildTool.createBasicInvocationRequest( pom, properties, goals, buildLog );
request.setUpdateSnapshots( false );
request.setShowErrors( true );
request.setDebug( true );
if ( switchLocalRepo )
{
request.setLocalRepositoryDirectory( localRepositoryDirectory );
}
InvocationResult result = buildTool.executeMaven( request );
if ( result.getExitCode() != 0 )
{
String buildLogUrl = buildLog.getAbsolutePath();
try
{
buildLogUrl = buildLog.toURL().toExternalForm();
}
catch ( MalformedURLException e )
{
}
throw new ExecutionFailedException( "Failed to execute build.\nPOM: " + pom + "\nGoals: " +
StringUtils.join( goals.iterator(), ", " ) + "\nExit Code: " + result.getExitCode() + "\nError: " +
result.getExecutionException() + "\nBuild Log: " + buildLogUrl + "\n", result );
}
}
protected MavenProject readProject( File pom )
throws TestToolsException
{
return projectTool.readProject( pom, localRepositoryDirectory );
}
protected String getPluginCLISpecification()
{
String pluginSpec = GROUP_ID + ":" + ARTIFACT_ID + ":" + VERSION + ":";
return pluginSpec;
}
protected void assertFileEquals( String mavenRepo, File expectedFile, File actualFile, File baseDir )
throws IOException
{
List expectedLines = getLines( mavenRepo, expectedFile );
if ( !actualFile.exists() )
{
throw new AssertionFailedError( "Expected file not found: " + actualFile.getAbsolutePath() );
}
List actualLines = getLines( mavenRepo, actualFile );
String filename = actualFile.getName();
for ( int i = 0; i < expectedLines.size(); i++ )
{
String expected = expectedLines.get( i ).toString();
// replace some vars in the expected line, to
// account
// for absolute paths that are different on each
// installation.
expected =
StringUtils.replace( expected, "${basedir}", Utils.convertToUnixStylePath( baseDir.getCanonicalPath() ) );
expected =
StringUtils.replace( expected, "${M2_TEST_REPO}",
Utils.convertToUnixStylePath( localRepositoryDirectory.getCanonicalPath() ) );
if ( actualLines.size() <= i )
{
fail( "Too few lines in the actual file. Was " + actualLines.size() + ", expected: " +
expectedLines.size() );
}
String actual = actualLines.get( i ).toString();
if ( expected.startsWith( "#" ) && actual.startsWith( "#" ) )
{
// ignore comments, for settings file
continue;
}
assertEquals( "Checking " + filename + ", line #" + ( i + 1 ), expected, actual );
}
assertTrue( "Unequal number of lines.", expectedLines.size() == actualLines.size() );
}
private List getLines( String mavenRepo, File file )
throws IOException
{
List lines = new ArrayList();
BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( file ), "UTF-8" ) );
String line;
while ( ( line = reader.readLine() ) != null )
{
lines.add( line );
}
IOUtil.close( reader );
return lines;
}
/**
* @param basedir
* @param projectOutputDir
* @throws IOException
*/
private void compareDirectoryContent( File basedir, File projectOutputDir, String additionalDir )
throws IOException
{
File expectedConfigDir = new File( basedir, "expected" + File.separator + additionalDir );
if ( expectedConfigDir.isDirectory() )
{
File[] files = expectedConfigDir.listFiles( new FileFilter()
{
public boolean accept( File file )
{
return !file.isDirectory();
}
} );
for ( int j = 0; j < files.length; j++ )
{
File expectedFile = files[j];
File actualFile =
new File( projectOutputDir, additionalDir + expectedFile.getName() ).getCanonicalFile();
if ( !actualFile.exists() )
{
throw new AssertionFailedError( "Expected file not found: " + actualFile.getAbsolutePath() );
}
assertFileEquals( localRepositoryDirectory.getCanonicalPath(), expectedFile, actualFile, basedir );
}
}
}
}