package org.codehaus.mojo.exec;
/*
* Copyright 2005 The Codehaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.SystemStreamLog;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import org.codehaus.plexus.util.StringOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.OS;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
/**
* @author Jerome Lacoste <jerome@coffeebreaks.org>
* @version $Id$
*/
public class ExecMojoTest
extends AbstractMojoTestCase
{
private MockExecMojo mojo;
static class MockExecMojo
extends ExecMojo
{
public int executeResult;
public List commandLines = new ArrayList();
public String failureMsg;
public Map systemProperties = new HashMap();
protected int executeCommandLine( Executor exec, CommandLine commandLine, Map enviro, OutputStream out, OutputStream err )
throws IOException, ExecuteException
{
commandLines.add( commandLine );
if ( failureMsg != null )
{
throw new ExecuteException( failureMsg, executeResult );
}
return executeResult;
}
protected String getSystemProperty( String key )
{
return (String) systemProperties.get( key );
}
int getAmountExecutedCommandLines() {
return commandLines.size();
}
CommandLine getExecutedCommandline( int index ) {
return ((CommandLine) commandLines.get( index ));
}
}
public void setUp()
throws Exception
{
super.setUp();
mojo = new MockExecMojo();
// note: most of the tests below assume that the specified
// executable path is not fully specicied. See ExecMojo#getExecutablePath
mojo.setExecutable( "mvn" );
mojo.setArguments( Arrays.asList( new String[]{"--version"} ) );
mojo.executeResult = 0;
mojo.setBasedir( File.createTempFile( "mvn-temp", "txt" ).getParentFile() );
}
/**
*/
public void testRunOK()
throws MojoExecutionException
{
mojo.execute();
checkMojo( "mvn --version" );
}
/*
This one won't work yet
public void xxtestSimpleRunPropertiesAndArguments()
throws MojoExecutionException, Exception
{
File pom = new File( getBasedir(), "src/test/projects/project1/pom.xml" );
String output = execute( pom, "exec" );
System.out.println(" OUTPUT" + output + "\n\n\n");
String expectedOutput = "arg.arg1\narg.arg2\nproject.env1=value1"; // FIXME should work on Windows as well
assertEquals( expectedOutput, output );
}
*/
/**
* integration test...
* - compile the Test class using mvn clean compile
* - run the test file using java, use it to generate a file whose contains are compared to expected output
*/
/*
public void testRunOKWithAutoComputedClasspath()
throws MojoExecutionException, Exception
{
String projectName = "project1";
ExecMojo mojo = new ExecMojo();
setUpProject( projectName, mojo );
// compile project
mojo.setExecutable( "mvn" );
mojo.setWorkingDirectory( new File( "src/test/projects/" + projectName + "/" ) );
mojo.setArguments( Arrays.asList( new String[]{"clean", "compile"} ) );
mojo.execute();
mojo.getLog().info( "executed mvn clean compile" );
// the command executes the test class
mojo.setExecutable( "java" );
mojo.setWorkingDirectory( (File) null );
Classpath classpath = new Classpath();
mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath,
"org.codehaus.mojo.exec.test.Test",
new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1",
"arg2"} ) );
mojo.execute();
// checking the command line would involve resolving the repository
// checkMojo( "java -cp" );
assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ),
getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) );
// the command executes the test class, this time specifying the dependencies
mojo.setExecutable( "java" );
mojo.setWorkingDirectory( (File) null );
classpath = new Classpath();
List dependencies = new ArrayList();
dependencies.add( "commons-io:commons-io" );
classpath.setDependencies( dependencies );
mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath,
"org.codehaus.mojo.exec.test.Test",
new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1",
"arg2"} ) );
mojo.execute();
// checking the command line would involve resolving the repository
// checkMojo( "java -cp" );
assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ),
getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) );
}
*/
/**
* @return output from System.out during mojo execution
*/
private String execute( File pom, String goal ) throws Exception {
ExecMojo mojo;
mojo = (ExecMojo) lookupMojo( goal, pom );
setUpProject( pom, mojo );
MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );
// why isn't this set up by the harness based on the default-value? TODO get to bottom of this!
// setVariableValueToObject( mojo, "includeProjectDependencies", Boolean.TRUE );
// setVariableValueToObject( mojo, "killAfter", new Long( -1 ) );
assertNotNull( mojo );
assertNotNull( project );
// trap System.out
PrintStream out = System.out;
StringOutputStream stringOutputStream = new StringOutputStream();
System.setOut( new PrintStream( stringOutputStream ) );
// ensure we don't log unnecessary stuff which would interfere with assessing success of tests
mojo.setLog( new DefaultLog( new ConsoleLogger( Logger.LEVEL_ERROR, "exec:exec" ) ) );
try
{
mojo.execute();
}
catch ( Throwable e )
{
e.printStackTrace( System.err );
fail( e.getMessage() );
}
finally
{
System.setOut( out );
}
return stringOutputStream.toString();
}
private void setUpProject( File pomFile, ExecMojo mojo )
throws Exception
{
MavenProjectBuilder builder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
ArtifactRepositoryLayout localRepositoryLayout =
(ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, "default" );
String path = "src/test/repository";
ArtifactRepository localRepository = new DefaultArtifactRepository( "local", "file://" +
new File( path ).getAbsolutePath(), localRepositoryLayout );
mojo.setBasedir( File.createTempFile( "mvn-temp", "txt" ).getParentFile() );
MavenProject project = builder.buildWithDependencies( pomFile, localRepository, null );
// this gets the classes for these tests of this mojo (exec plugin) onto the project classpath for the test
project.getBuild().setOutputDirectory( new File( "target/test-classes" ).getAbsolutePath() );
mojo.setProject( project );
mojo.setLog( new SystemStreamLog()
{
public boolean isDebugEnabled()
{
return true;
}
} );
}
// MEXEC-12, MEXEC-72
public void testGetExecutablePath() throws IOException
{
ExecMojo realMojo = new ExecMojo();
File workdir = new File( System.getProperty( "user.dir" ) );
Map enviro = new HashMap();
String myJavaPath = "target" + File.separator + "javax";
File f = new File( myJavaPath );
assertTrue( "file created...", f.createNewFile() );
assertTrue( "file exists...", f.exists() );
realMojo.setExecutable( myJavaPath );
CommandLine cmd = realMojo.getExecutablePath(enviro, workdir);
assertTrue( "File exists so path is absolute",
cmd.getExecutable().startsWith( System.getProperty( "user.dir" ) ) );
f.delete();
assertFalse( "file deleted...", f.exists() );
cmd = realMojo.getExecutablePath(enviro, workdir);
assertEquals( "File doesn't exist. Let the system find it (in that PATH?)",
myJavaPath, cmd.getExecutable() );
if ( OS.isFamilyWindows() ) //how to make this part of the test run on other platforms as well??
{
myJavaPath = "target" + File.separator + "javax.bat";
f = new File( myJavaPath );
assertTrue( "file created...", f.createNewFile() );
assertTrue( "file exists...", f.exists() );
realMojo.setExecutable( "javax.bat" );
cmd = realMojo.getExecutablePath( enviro, workdir );
assertTrue( "is bat file on windows, execute using cmd.",
cmd.getExecutable().equals( "cmd" ) );
enviro.put( "PATH", workdir.getAbsolutePath() + File.separator + "target" );
cmd = realMojo.getExecutablePath( enviro, workdir );
assertTrue( "is bat file on windows' PATH, execute using cmd.",
cmd.getExecutable().equals( "cmd" ) );
f.delete();
assertFalse( "file deleted...", f.exists() );
}
}
public void testRunFailure()
{
mojo.executeResult = 1;
try
{
mojo.execute();
fail( "expected failure" );
}
catch ( MojoExecutionException e )
{
assertEquals( "Result of " + mojo.getExecutedCommandline( 0 ) + " execution is: '1'.",
e.getMessage() );
}
checkMojo( "mvn --version" );
}
public void testRunError()
{
mojo.failureMsg = "simulated failure";
try
{
mojo.execute();
fail( "expected failure" );
}
catch ( MojoExecutionException e )
{
assertEquals( "Command execution failed.", e.getMessage() );
}
checkMojo( "mvn --version" );
}
public void testOverrides()
throws MojoExecutionException
{
mojo.systemProperties.put( "exec.args", "-f pom.xml" );
mojo.execute();
checkMojo( "mvn -f pom.xml" );
}
public void testOverrides3()
throws MojoExecutionException
{
mojo.systemProperties.put( "exec.args", null );
mojo.execute();
checkMojo( "mvn --version" );
mojo.commandLines.clear();
mojo.systemProperties.put( "exec.args", "" );
mojo.execute();
checkMojo( "mvn --version" );
}
public void testIsResultCodeAFailure()
{
ExecMojo execMojo = new ExecMojo();
assertTrue(execMojo.isResultCodeAFailure(1));
assertFalse(execMojo.isResultCodeAFailure(0));
execMojo.setSuccessCodes(new ArrayList());
assertTrue(execMojo.isResultCodeAFailure(1));
assertFalse(execMojo.isResultCodeAFailure(0));
execMojo.setSuccessCodes(Arrays.asList(new String[] { "2", "5" }));
assertTrue(execMojo.isResultCodeAFailure(0));
assertTrue(execMojo.isResultCodeAFailure(10));
assertFalse(execMojo.isResultCodeAFailure(2));
assertFalse(execMojo.isResultCodeAFailure(5));
}
// MEXEC-81
public void testParseCommandlineOSWin() throws Exception
{
ExecMojo execMojo = new ExecMojo();
final String javaHome = "C:\\Java\\jdk1.5.0_15";
// can only be set by expression or plugin-configuration
setVariableValueToObject( execMojo, "commandlineArgs", javaHome );
String[] args = execMojo.parseCommandlineArgs();
assertEquals( javaHome, args[0] );
}
private void checkMojo( String expectedCommandLine )
{
assertEquals( 1, mojo.getAmountExecutedCommandLines() );
CommandLine commandline = mojo.getExecutedCommandline( 0 );
// do NOT depend on Commandline toString()
assertEquals(expectedCommandLine, getCommandLineAsString( commandline ));
}
private String getCommandLineAsString( CommandLine commandline ) {
//for the sake of the test comparisons, cut out the eventual
//cmd /c *.bat conversion
String result = commandline.getExecutable();
boolean isCmd = false;
if (OS.isFamilyWindows() && result.equals("cmd")) {
result = "";
isCmd = true;
}
String[] arguments = commandline.getArguments();
for (int i = 0; i < arguments.length; i++)
{
String arg = arguments[i];
if (isCmd && i == 0 && "/c".equals(arg)) {
continue;
}
if (isCmd && i == 1 && arg.endsWith( ".bat")) {
arg = arg.substring( 0, arg.length() - ".bat".length());
}
result += (result.length() == 0 ? "" : " ") + arg;
}
return result;
}
// TAKEN FROM NetbeansFreeformPluginTest - refactor ?
/**
* This method asserts that the two given files are equals in their
* content.
*
* @param mavenRepo Not used.
* @param expectedFile The file that is expected.
* @param actualFile The file that is.
* @throws java.io.IOException if something goes wrong.
*/
private void assertFileEquals( String mavenRepo, File expectedFile, File actualFile )
throws IOException
{
List expectedLines = getLines( mavenRepo, expectedFile );
List actualLines = getLines( mavenRepo, actualFile );
for ( int i = 0; i < expectedLines.size(); i++ )
{
String expected = expectedLines.get( i ).toString();
if ( actualLines.size() < i )
{
fail( "Too few lines in the actual file. Was " + actualLines.size() + ", expected: " +
expectedLines.size() );
}
String actual = actualLines.get( i ).toString();
assertEquals( "Checking line #" + ( i + 1 ), expected, actual );
}
assertTrue( "Unequal number of lines.", expectedLines.size() == actualLines.size() );
}
/**
* This method gives the list of String in a file.
*
* @param mavenRepo Not used.
* @param file The file to be read.
* @return The list of the lines of the file.
* @throws java.io.IOException if something goes wrong.
*/
private List getLines( String mavenRepo, File file )
throws IOException
{
List lines = new ArrayList();
BufferedReader reader = new BufferedReader( new FileReader( file ) );
String line;
while ( ( line = reader.readLine() ) != null )
{
lines.add(
line ); //StringUtils.replace( line, "#ArtifactRepositoryPath#", mavenRepo.replace( '\\', '/' ) ) );
}
return lines;
}
}