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 }