001 package org.codehaus.mojo.exec; 002 003 /* 004 * Copyright 2005 The Codehaus. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 import org.apache.maven.artifact.repository.ArtifactRepository; 020 import org.apache.maven.artifact.repository.DefaultArtifactRepository; 021 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; 022 import org.apache.maven.plugin.MojoExecutionException; 023 import org.apache.maven.plugin.logging.SystemStreamLog; 024 import org.apache.maven.project.MavenProject; 025 import org.apache.maven.project.MavenProjectBuilder; 026 027 import java.io.BufferedReader; 028 import java.io.File; 029 import java.io.FileReader; 030 import java.io.IOException; 031 import java.io.OutputStream; 032 import java.io.PrintStream; 033 import org.codehaus.plexus.util.StringOutputStream; 034 import java.util.ArrayList; 035 import java.util.Arrays; 036 import java.util.Collections; 037 import java.util.HashMap; 038 import java.util.List; 039 import java.util.Map; 040 import org.apache.commons.exec.CommandLine; 041 import org.apache.commons.exec.ExecuteException; 042 import org.apache.commons.exec.Executor; 043 import org.apache.commons.exec.OS; 044 import org.codehaus.plexus.logging.Logger; 045 import org.codehaus.plexus.logging.console.ConsoleLogger; 046 import org.apache.maven.monitor.logging.DefaultLog; 047 import org.apache.maven.plugin.testing.AbstractMojoTestCase; 048 049 /** 050 * @author Jerome Lacoste <jerome@coffeebreaks.org> 051 * @version $Id: ExecMojoTest.java 12372 2010-07-09 20:51:00Z rfscholte $ 052 */ 053 public class ExecMojoTest 054 extends AbstractMojoTestCase 055 { 056 private MockExecMojo mojo; 057 058 static class MockExecMojo 059 extends ExecMojo 060 { 061 public int executeResult; 062 063 public List commandLines = new ArrayList(); 064 065 public String failureMsg; 066 067 public Map systemProperties = new HashMap(); 068 069 protected int executeCommandLine( Executor exec, CommandLine commandLine, Map enviro, OutputStream out, OutputStream err ) 070 throws IOException, ExecuteException 071 { 072 commandLines.add( commandLine ); 073 if ( failureMsg != null ) 074 { 075 throw new ExecuteException( failureMsg, executeResult ); 076 } 077 return executeResult; 078 } 079 080 protected String getSystemProperty( String key ) 081 { 082 return (String) systemProperties.get( key ); 083 } 084 085 int getAmountExecutedCommandLines() { 086 return commandLines.size(); 087 } 088 089 CommandLine getExecutedCommandline( int index ) { 090 return ((CommandLine) commandLines.get( index )); 091 } 092 } 093 094 public void setUp() 095 throws Exception 096 { 097 super.setUp(); 098 mojo = new MockExecMojo(); 099 // note: most of the tests below assume that the specified 100 // executable path is not fully specicied. See ExecMojo#getExecutablePath 101 mojo.setExecutable( "mvn" ); 102 mojo.setArguments( Arrays.asList( new String[]{"--version"} ) ); 103 mojo.executeResult = 0; 104 mojo.setBasedir( File.createTempFile( "mvn-temp", "txt" ).getParentFile() ); 105 } 106 107 /** 108 */ 109 public void testRunOK() 110 throws MojoExecutionException 111 { 112 mojo.execute(); 113 114 checkMojo( "mvn --version" ); 115 } 116 117 /* 118 This one won't work yet 119 public void xxtestSimpleRunPropertiesAndArguments() 120 throws MojoExecutionException, Exception 121 { 122 File pom = new File( getBasedir(), "src/test/projects/project1/pom.xml" ); 123 124 String output = execute( pom, "exec" ); 125 126 System.out.println(" OUTPUT" + output + "\n\n\n"); 127 128 String expectedOutput = "arg.arg1\narg.arg2\nproject.env1=value1"; // FIXME should work on Windows as well 129 130 assertEquals( expectedOutput, output ); 131 } 132 */ 133 134 /** 135 * integration test... 136 * - compile the Test class using mvn clean compile 137 * - run the test file using java, use it to generate a file whose contains are compared to expected output 138 */ 139 /* 140 public void testRunOKWithAutoComputedClasspath() 141 throws MojoExecutionException, Exception 142 { 143 String projectName = "project1"; 144 145 ExecMojo mojo = new ExecMojo(); 146 147 setUpProject( projectName, mojo ); 148 149 // compile project 150 mojo.setExecutable( "mvn" ); 151 mojo.setWorkingDirectory( new File( "src/test/projects/" + projectName + "/" ) ); 152 mojo.setArguments( Arrays.asList( new String[]{"clean", "compile"} ) ); 153 154 mojo.execute(); 155 156 mojo.getLog().info( "executed mvn clean compile" ); 157 158 // the command executes the test class 159 mojo.setExecutable( "java" ); 160 mojo.setWorkingDirectory( (File) null ); 161 Classpath classpath = new Classpath(); 162 mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath, 163 "org.codehaus.mojo.exec.test.Test", 164 new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1", 165 "arg2"} ) ); 166 167 mojo.execute(); 168 169 // checking the command line would involve resolving the repository 170 // checkMojo( "java -cp" ); 171 172 assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ), 173 getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) ); 174 175 // the command executes the test class, this time specifying the dependencies 176 mojo.setExecutable( "java" ); 177 mojo.setWorkingDirectory( (File) null ); 178 classpath = new Classpath(); 179 List dependencies = new ArrayList(); 180 dependencies.add( "commons-io:commons-io" ); 181 classpath.setDependencies( dependencies ); 182 mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath, 183 "org.codehaus.mojo.exec.test.Test", 184 new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1", 185 "arg2"} ) ); 186 187 mojo.execute(); 188 189 // checking the command line would involve resolving the repository 190 // checkMojo( "java -cp" ); 191 192 assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ), 193 getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) ); 194 } 195 */ 196 197 /** 198 * @return output from System.out during mojo execution 199 */ 200 private String execute( File pom, String goal ) throws Exception { 201 202 ExecMojo mojo; 203 mojo = (ExecMojo) lookupMojo( goal, pom ); 204 205 setUpProject( pom, mojo ); 206 207 MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); 208 209 // why isn't this set up by the harness based on the default-value? TODO get to bottom of this! 210 // setVariableValueToObject( mojo, "includeProjectDependencies", Boolean.TRUE ); 211 // setVariableValueToObject( mojo, "killAfter", new Long( -1 ) ); 212 213 assertNotNull( mojo ); 214 assertNotNull( project ); 215 216 // trap System.out 217 PrintStream out = System.out; 218 StringOutputStream stringOutputStream = new StringOutputStream(); 219 System.setOut( new PrintStream( stringOutputStream ) ); 220 // ensure we don't log unnecessary stuff which would interfere with assessing success of tests 221 mojo.setLog( new DefaultLog( new ConsoleLogger( Logger.LEVEL_ERROR, "exec:exec" ) ) ); 222 223 try 224 { 225 mojo.execute(); 226 } 227 catch ( Throwable e ) 228 { 229 e.printStackTrace( System.err ); 230 fail( e.getMessage() ); 231 } 232 finally 233 { 234 System.setOut( out ); 235 } 236 237 return stringOutputStream.toString(); 238 } 239 240 241 private void setUpProject( File pomFile, ExecMojo mojo ) 242 throws Exception 243 { 244 MavenProjectBuilder builder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE ); 245 246 ArtifactRepositoryLayout localRepositoryLayout = 247 (ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, "default" ); 248 249 String path = "src/test/repository"; 250 251 ArtifactRepository localRepository = new DefaultArtifactRepository( "local", "file://" + 252 new File( path ).getAbsolutePath(), localRepositoryLayout ); 253 254 mojo.setBasedir( File.createTempFile( "mvn-temp", "txt" ).getParentFile() ); 255 256 MavenProject project = builder.buildWithDependencies( pomFile, localRepository, null ); 257 258 // this gets the classes for these tests of this mojo (exec plugin) onto the project classpath for the test 259 project.getBuild().setOutputDirectory( new File( "target/test-classes" ).getAbsolutePath() ); 260 261 mojo.setProject( project ); 262 263 mojo.setLog( new SystemStreamLog() 264 { 265 public boolean isDebugEnabled() 266 { 267 return true; 268 } 269 } ); 270 } 271 272 // MEXEC-12, MEXEC-72 273 public void testGetExecutablePath() throws IOException 274 { 275 276 ExecMojo realMojo = new ExecMojo(); 277 278 File workdir = new File( System.getProperty( "user.dir" ) ); 279 Map enviro = new HashMap(); 280 281 String myJavaPath = "target" + File.separator + "javax"; 282 File f = new File( myJavaPath ); 283 assertTrue( "file created...", f.createNewFile() ); 284 assertTrue( "file exists...", f.exists() ); 285 286 realMojo.setExecutable( myJavaPath ); 287 288 CommandLine cmd = realMojo.getExecutablePath(enviro, workdir); 289 assertTrue( "File exists so path is absolute", 290 cmd.getExecutable().startsWith( System.getProperty( "user.dir" ) ) ); 291 292 f.delete(); 293 assertFalse( "file deleted...", f.exists() ); 294 cmd = realMojo.getExecutablePath(enviro, workdir); 295 assertEquals( "File doesn't exist. Let the system find it (in that PATH?)", 296 myJavaPath, cmd.getExecutable() ); 297 298 299 if ( OS.isFamilyWindows() ) //how to make this part of the test run on other platforms as well?? 300 { 301 302 myJavaPath = "target" + File.separator + "javax.bat"; 303 f = new File( myJavaPath ); 304 assertTrue( "file created...", f.createNewFile() ); 305 assertTrue( "file exists...", f.exists() ); 306 307 308 realMojo.setExecutable( "javax.bat" ); 309 cmd = realMojo.getExecutablePath( enviro, workdir ); 310 assertTrue( "is bat file on windows, execute using cmd.", 311 cmd.getExecutable().equals( "cmd" ) ); 312 313 enviro.put( "PATH", workdir.getAbsolutePath() + File.separator + "target" ); 314 cmd = realMojo.getExecutablePath( enviro, workdir ); 315 assertTrue( "is bat file on windows' PATH, execute using cmd.", 316 cmd.getExecutable().equals( "cmd" ) ); 317 f.delete(); 318 assertFalse( "file deleted...", f.exists() ); 319 } 320 } 321 322 public void testRunFailure() 323 { 324 mojo.executeResult = 1; 325 326 try 327 { 328 mojo.execute(); 329 fail( "expected failure" ); 330 } 331 catch ( MojoExecutionException e ) 332 { 333 assertEquals( "Result of " + mojo.getExecutedCommandline( 0 ) + " execution is: '1'.", 334 e.getMessage() ); 335 } 336 337 checkMojo( "mvn --version" ); 338 } 339 340 public void testRunError() 341 { 342 mojo.failureMsg = "simulated failure"; 343 344 try 345 { 346 mojo.execute(); 347 fail( "expected failure" ); 348 } 349 catch ( MojoExecutionException e ) 350 { 351 assertEquals( "Command execution failed.", e.getMessage() ); 352 } 353 354 checkMojo( "mvn --version" ); 355 } 356 357 public void testOverrides() 358 throws MojoExecutionException 359 { 360 mojo.systemProperties.put( "exec.args", "-f pom.xml" ); 361 mojo.execute(); 362 363 checkMojo( "mvn -f pom.xml" ); 364 } 365 366 public void testOverrides3() 367 throws MojoExecutionException 368 { 369 mojo.systemProperties.put( "exec.args", null ); 370 mojo.execute(); 371 372 checkMojo( "mvn --version" ); 373 374 mojo.commandLines.clear(); 375 mojo.systemProperties.put( "exec.args", "" ); 376 mojo.execute(); 377 378 checkMojo( "mvn --version" ); 379 } 380 381 public void testIsResultCodeAFailure() 382 { 383 ExecMojo execMojo = new ExecMojo(); 384 assertTrue(execMojo.isResultCodeAFailure(1)); 385 assertFalse(execMojo.isResultCodeAFailure(0)); 386 387 execMojo.setSuccessCodes(new ArrayList()); 388 assertTrue(execMojo.isResultCodeAFailure(1)); 389 assertFalse(execMojo.isResultCodeAFailure(0)); 390 391 execMojo.setSuccessCodes(Arrays.asList(new String[] { "2", "5" })); 392 assertTrue(execMojo.isResultCodeAFailure(0)); 393 assertTrue(execMojo.isResultCodeAFailure(10)); 394 assertFalse(execMojo.isResultCodeAFailure(2)); 395 assertFalse(execMojo.isResultCodeAFailure(5)); 396 } 397 398 // MEXEC-81 399 public void testParseCommandlineOSWin() throws Exception 400 { 401 ExecMojo execMojo = new ExecMojo(); 402 final String javaHome = "C:\\Java\\jdk1.5.0_15"; 403 // can only be set by expression or plugin-configuration 404 setVariableValueToObject( execMojo, "commandlineArgs", javaHome ); 405 String[] args = execMojo.parseCommandlineArgs(); 406 assertEquals( javaHome, args[0] ); 407 } 408 409 private void checkMojo( String expectedCommandLine ) 410 { 411 assertEquals( 1, mojo.getAmountExecutedCommandLines() ); 412 CommandLine commandline = mojo.getExecutedCommandline( 0 ); 413 // do NOT depend on Commandline toString() 414 assertEquals(expectedCommandLine, getCommandLineAsString( commandline )); 415 } 416 417 private String getCommandLineAsString( CommandLine commandline ) { 418 //for the sake of the test comparisons, cut out the eventual 419 //cmd /c *.bat conversion 420 String result = commandline.getExecutable(); 421 boolean isCmd = false; 422 if (OS.isFamilyWindows() && result.equals("cmd")) { 423 result = ""; 424 isCmd = true; 425 } 426 String[] arguments = commandline.getArguments(); 427 for (int i = 0; i < arguments.length; i++) 428 { 429 String arg = arguments[i]; 430 if (isCmd && i == 0 && "/c".equals(arg)) { 431 continue; 432 } 433 if (isCmd && i == 1 && arg.endsWith( ".bat")) { 434 arg = arg.substring( 0, arg.length() - ".bat".length()); 435 } 436 result += (result.length() == 0 ? "" : " ") + arg; 437 } 438 return result; 439 } 440 441 // TAKEN FROM NetbeansFreeformPluginTest - refactor ? 442 443 /** 444 * This method asserts that the two given files are equals in their 445 * content. 446 * 447 * @param mavenRepo Not used. 448 * @param expectedFile The file that is expected. 449 * @param actualFile The file that is. 450 * @throws java.io.IOException if something goes wrong. 451 */ 452 private void assertFileEquals( String mavenRepo, File expectedFile, File actualFile ) 453 throws IOException 454 { 455 List expectedLines = getLines( mavenRepo, expectedFile ); 456 457 List actualLines = getLines( mavenRepo, actualFile ); 458 459 for ( int i = 0; i < expectedLines.size(); i++ ) 460 { 461 String expected = expectedLines.get( i ).toString(); 462 463 if ( actualLines.size() < i ) 464 { 465 fail( "Too few lines in the actual file. Was " + actualLines.size() + ", expected: " + 466 expectedLines.size() ); 467 } 468 469 String actual = actualLines.get( i ).toString(); 470 471 assertEquals( "Checking line #" + ( i + 1 ), expected, actual ); 472 } 473 474 assertTrue( "Unequal number of lines.", expectedLines.size() == actualLines.size() ); 475 } 476 477 /** 478 * This method gives the list of String in a file. 479 * 480 * @param mavenRepo Not used. 481 * @param file The file to be read. 482 * @return The list of the lines of the file. 483 * @throws java.io.IOException if something goes wrong. 484 */ 485 private List getLines( String mavenRepo, File file ) 486 throws IOException 487 { 488 List lines = new ArrayList(); 489 490 BufferedReader reader = new BufferedReader( new FileReader( file ) ); 491 492 String line; 493 494 while ( ( line = reader.readLine() ) != null ) 495 { 496 lines.add( 497 line ); //StringUtils.replace( line, "#ArtifactRepositoryPath#", mavenRepo.replace( '\\', '/' ) ) ); 498 } 499 500 return lines; 501 } 502 }