View Javadoc
1   package org.apache.maven.shared.release.exec;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static org.mockito.Matchers.endsWith;
23  import static org.mockito.Matchers.eq;
24  import static org.mockito.Matchers.isA;
25  import static org.mockito.Matchers.isNull;
26  import static org.mockito.Mockito.mock;
27  import static org.mockito.Mockito.spy;
28  import static org.mockito.Mockito.times;
29  import static org.mockito.Mockito.verify;
30  import static org.mockito.Mockito.verifyNoMoreInteractions;
31  import static org.mockito.Mockito.when;
32  
33  import java.io.File;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.io.Writer;
37  
38  import org.apache.maven.settings.Proxy;
39  import org.apache.maven.settings.Server;
40  import org.apache.maven.settings.Settings;
41  import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
42  import org.apache.maven.shared.release.ReleaseResult;
43  import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
44  import org.apache.maven.shared.release.env.ReleaseEnvironment;
45  import org.codehaus.plexus.PlexusTestCase;
46  import org.codehaus.plexus.util.cli.Arg;
47  import org.codehaus.plexus.util.cli.CommandLineException;
48  import org.codehaus.plexus.util.cli.Commandline;
49  import org.mockito.ArgumentCaptor;
50  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
51  
52  /**
53   * Test the forked Maven executor.
54   *
55   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
56   */
57  public class ForkedMavenExecutorTest
58      extends PlexusTestCase
59  {
60      private ForkedMavenExecutor executor;
61      
62      private SecDispatcher secDispatcher;
63  
64      protected void setUp()
65          throws Exception
66      {
67          super.setUp();
68  
69          executor = (ForkedMavenExecutor) lookup( MavenExecutor.ROLE, "forked-path" );
70          
71          secDispatcher = (SecDispatcher) lookup( SecDispatcher.ROLE, "mng-4384" );
72      }
73  
74      public void testExecution()
75          throws Exception
76      {
77          // prepare
78          File workingDirectory = getTestFile( "target/working-directory" );
79          Process mockProcess = mock( Process.class );
80          when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
81          when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
82          when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
83          when( mockProcess.waitFor() ).thenReturn( 0 );
84  
85          Commandline commandLineMock = mock( Commandline.class );
86          when( commandLineMock.execute() ).thenReturn( mockProcess );
87  
88          Arg valueArgument = mock( Arg.class );
89          when( commandLineMock.createArg() ).thenReturn( valueArgument );
90          
91          CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
92          when( commandLineFactoryMock.createCommandLine( isA( String.class ) /*"mvn"*/ ) ).thenReturn( commandLineMock );
93  
94          executor.setCommandLineFactory( commandLineFactoryMock );
95  
96          // execute
97          executor.executeGoals( workingDirectory, "clean integration-test", false, null, new ReleaseResult() );
98  
99          // verify
100         verify( mockProcess ).getInputStream();
101         verify( mockProcess ).getErrorStream();
102         verify( mockProcess ).getOutputStream();
103         verify( mockProcess ).waitFor();
104         verify( commandLineMock ).setWorkingDirectory( workingDirectory.getAbsolutePath() );
105         verify( commandLineMock ).addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
106         verify( commandLineMock ).addEnvironment( eq( "M2_HOME" ), isNull( String.class ) );
107         verify( commandLineMock ).execute();
108         verify( commandLineMock, times( 4 ) ).createArg();
109         verify( valueArgument ).setValue( "clean" );
110         verify( valueArgument ).setValue( "integration-test" );
111         verify( valueArgument ).setValue( "--no-plugin-updates" );
112         verify( valueArgument ).setValue( "--batch-mode" );
113         verify( commandLineFactoryMock ).createCommandLine( endsWith( "mvn" ) );
114         
115         verifyNoMoreInteractions( mockProcess, commandLineFactoryMock, commandLineMock, valueArgument );
116     }
117 
118     public void testExecutionWithCustomPomFile()
119         throws Exception
120     {
121         File workingDirectory = getTestFile( "target/working-directory" );
122         Process mockProcess = mock( Process.class );
123         when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
124         when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
125         when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
126         when( mockProcess.waitFor() ).thenReturn( 0 );
127         
128         Commandline commandLineMock = mock( Commandline.class );
129         when( commandLineMock.execute() ).thenReturn( mockProcess );
130         
131         Arg argMock = mock( Arg.class );
132         when( commandLineMock.createArg() ).thenReturn( argMock );
133         
134         CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
135         when( commandLineFactoryMock.createCommandLine( isA( String.class ) /* "mvn" */ ) ).thenReturn( commandLineMock );
136 
137         executor.setCommandLineFactory( commandLineFactoryMock );
138 
139         // execute
140         executor.executeGoals( workingDirectory, "clean integration-test", false, null, "my-pom.xml",
141                                new ReleaseResult() );
142         // verify
143         verify( mockProcess ).getInputStream();
144         verify( mockProcess ).getErrorStream();
145         verify( mockProcess ).getOutputStream();
146         verify( mockProcess ).waitFor();
147         verify( commandLineMock ).setWorkingDirectory( workingDirectory.getAbsolutePath() );
148         verify( commandLineMock ).addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
149         verify( commandLineMock ).addEnvironment( eq( "M2_HOME" ), isNull( String.class ) );
150         verify( commandLineMock ).execute();
151         verify( commandLineMock, times( 6 ) ).createArg();
152         verify( argMock ).setValue( "clean" );
153         verify( argMock ).setValue( "integration-test" );
154         verify( argMock ).setValue( "-f" );
155         verify( argMock ).setValue( "my-pom.xml" );
156         verify( argMock ).setValue( "--no-plugin-updates" );
157         verify( argMock ).setValue( "--batch-mode" );
158         verify( commandLineFactoryMock ).createCommandLine( endsWith( "mvn" ) );
159         
160         verifyNoMoreInteractions( mockProcess, commandLineMock, argMock, commandLineFactoryMock );
161     }
162 
163     public void testExecutionWithArguments()
164         throws Exception
165     {
166         File workingDirectory = getTestFile( "target/working-directory" );
167         Process mockProcess = mock( Process.class );
168         when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
169         when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
170         when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
171         when( mockProcess.waitFor() ).thenReturn( 0 );
172 
173         Commandline commandLineMock = mock( Commandline.class );
174         when( commandLineMock.execute() ).thenReturn( mockProcess );
175         
176         Arg argMock = mock( Arg.class );
177         when( commandLineMock.createArg() ).thenReturn( argMock );
178 
179         CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
180         when( commandLineFactoryMock.createCommandLine( endsWith( "mvn" ) ) ).thenReturn( commandLineMock );
181 
182         executor.setCommandLineFactory( commandLineFactoryMock );
183 
184         // execute
185         String arguments = "-DperformRelease=true -Dmaven.test.skip=true";
186         executor.executeGoals( workingDirectory, "clean integration-test", false, arguments, new ReleaseResult() );
187 
188         // verify
189         verify( mockProcess ).getInputStream();
190         verify( mockProcess ).getErrorStream();
191         verify( mockProcess ).getOutputStream();
192         verify( mockProcess ).waitFor();
193         verify( commandLineMock ).setWorkingDirectory( workingDirectory.getAbsolutePath() );
194         verify( commandLineMock ).addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
195         verify( commandLineMock ).addEnvironment( eq( "M2_HOME" ), isNull( String.class ) );
196         verify( commandLineMock ).execute();
197         verify( commandLineMock, times( 5 ) ).createArg();
198         verify( argMock ).setValue( "clean" );
199         verify( argMock ).setValue( "integration-test" );
200         verify( argMock ).setValue( "--no-plugin-updates" );
201         verify( argMock ).setValue( "--batch-mode" );
202         verify( argMock ).setLine( "-DperformRelease=true -Dmaven.test.skip=true" );
203         verify( commandLineFactoryMock ).createCommandLine( endsWith( "mvn" ) );
204         
205         verifyNoMoreInteractions( mockProcess, commandLineMock, argMock, commandLineFactoryMock );
206     }
207 
208     public void testExecutionWithNonZeroExitCode()
209         throws Exception
210     {
211         // prepare
212         File workingDirectory = getTestFile( "target/working-directory" );
213         Process mockProcess = mock( Process.class );
214         when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
215         when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
216         when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
217         when( mockProcess.waitFor() ).thenReturn( 1 );
218         when( mockProcess.exitValue() ).thenReturn( 1 ); // why was this here in the original test?
219 
220         Commandline commandLineMock = mock( Commandline.class );
221         when( commandLineMock.execute() ).thenReturn( mockProcess );
222         
223         Arg argMock = mock( Arg.class );
224         when( commandLineMock.createArg() ).thenReturn( argMock );
225         
226         CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
227         when( commandLineFactoryMock.createCommandLine( endsWith( "mvn" ) ) ).thenReturn( commandLineMock );
228 
229         executor.setCommandLineFactory( commandLineFactoryMock );
230 
231         // execute
232         try
233         {
234             executor.executeGoals( workingDirectory, "clean integration-test", false, null, new ReleaseResult() );
235 
236             fail( "Should have thrown an exception" );
237         }
238         catch ( MavenExecutorException e )
239         {
240             assertEquals( "Check exit code", 1, e.getExitCode() );
241         }
242         
243         // verify
244         verify( mockProcess ).getInputStream();
245         verify( mockProcess ).getErrorStream();
246         verify( mockProcess ).getOutputStream();
247         verify( mockProcess ).waitFor();
248 //        verify( mockProcess ).exitValue();
249         verify( commandLineMock ).setWorkingDirectory( workingDirectory.getAbsolutePath() );
250         verify( commandLineMock ).addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
251         verify( commandLineMock ).addEnvironment( eq( "M2_HOME" ), isNull( String.class ) );
252         verify( commandLineMock ).execute();
253         verify( commandLineMock, times( 4 ) ).createArg();
254         verify( argMock ).setValue( "clean" );
255         verify( argMock ).setValue( "integration-test" );
256         verify( argMock ).setValue( "--no-plugin-updates" );
257         verify( argMock ).setValue( "--batch-mode" );
258         verify( commandLineFactoryMock ).createCommandLine( endsWith( "mvn" ) );
259         
260         verifyNoMoreInteractions( mockProcess, commandLineMock, argMock, commandLineFactoryMock );
261     }
262 
263     public void testExecutionWithCommandLineException()
264         throws Exception
265     {
266         // prepare
267         File workingDirectory = getTestFile( "target/working-directory" );
268 
269         Commandline commandLineMock = mock( Commandline.class );
270         when( commandLineMock.execute() ).thenThrow( new CommandLineException( "..." ) );
271 
272         Arg argMock = mock( Arg.class );
273         when ( commandLineMock.createArg() ).thenReturn( argMock );
274         
275         CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
276         when( commandLineFactoryMock.createCommandLine( endsWith( "mvn" ) ) ).thenReturn( commandLineMock );
277         
278         executor.setCommandLineFactory( commandLineFactoryMock );
279 
280         // execute
281         try
282         {
283             executor.executeGoals( workingDirectory, "clean integration-test", false, null, new ReleaseResult() );
284 
285             fail( "Should have thrown an exception" );
286         }
287         catch ( MavenExecutorException e )
288         {
289             assertEquals( "Check cause", CommandLineException.class, e.getCause().getClass() );
290         }
291 
292         // verify
293         verify( commandLineMock ).setWorkingDirectory( workingDirectory.getAbsolutePath() );
294         verify( commandLineMock ).addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
295         verify( commandLineMock ).addEnvironment( eq( "M2_HOME" ), isNull( String.class ) );
296         verify( commandLineMock ).execute();
297         verify( commandLineMock, times( 4 ) ).createArg();
298         verify( argMock ).setValue( "clean" );
299         verify( argMock ).setValue( "integration-test" );
300         verify( argMock ).setValue( "--no-plugin-updates" );
301         verify( argMock ).setValue( "--batch-mode" );
302         verify( commandLineFactoryMock ).createCommandLine( endsWith( "mvn" ) );
303         
304         verifyNoMoreInteractions( commandLineMock, argMock, commandLineFactoryMock );
305     }
306     
307     public void testEncryptSettings()
308         throws Exception
309     {
310         // prepare
311         File workingDirectory = getTestFile( "target/working-directory" );
312         Process mockProcess = mock( Process.class );
313         when( mockProcess.getInputStream() ).thenReturn( mock( InputStream.class ) );
314         when( mockProcess.getErrorStream() ).thenReturn( mock( InputStream.class ) );
315         when( mockProcess.getOutputStream() ).thenReturn( mock( OutputStream.class ) );
316         when( mockProcess.waitFor() ).thenReturn( 0 );
317 
318         Commandline commandLineMock = mock( Commandline.class );
319         when( commandLineMock.execute() ).thenReturn( mockProcess );
320 
321         Arg valueArgument = mock( Arg.class );
322         when( commandLineMock.createArg() ).thenReturn( valueArgument );
323 
324         CommandLineFactory commandLineFactoryMock = mock( CommandLineFactory.class );
325         when( commandLineFactoryMock.createCommandLine( isA( String.class ) /* "mvn" */) ).thenReturn( commandLineMock );
326 
327         executor.setCommandLineFactory( commandLineFactoryMock );
328 
329         Settings settings = new Settings();
330         Server server = new Server();
331         server.setPassphrase( "server_passphrase" );
332         server.setPassword( "server_password" );
333         settings.addServer( server );
334         Proxy proxy = new Proxy();
335         proxy.setPassword( "proxy_password" );
336         settings.addProxy( proxy );
337 
338         ReleaseEnvironment releaseEnvironment = new DefaultReleaseEnvironment();
339         releaseEnvironment.setSettings( settings );
340 
341         AbstractMavenExecutor executorSpy = spy( executor );
342         SettingsXpp3Writer settingsWriter = mock( SettingsXpp3Writer.class );
343 
344         ArgumentCaptor<Settings> encryptedSettings = ArgumentCaptor.forClass( Settings.class );
345 
346         when( executorSpy.getSettingsWriter() ).thenReturn( settingsWriter );
347 
348         executorSpy.executeGoals( workingDirectory, "validate", releaseEnvironment, false, null, new ReleaseResult() );
349 
350         verify( settingsWriter ).write( isA( Writer.class ), encryptedSettings.capture() );
351 
352         assertNotSame( settings, encryptedSettings.getValue() );
353 
354         Server encryptedServer = encryptedSettings.getValue().getServers().get( 0 );
355         assertEquals( "server_passphrase", secDispatcher.decrypt( encryptedServer.getPassphrase() ) );
356         assertEquals( "server_password", secDispatcher.decrypt( encryptedServer.getPassword() ) );
357 
358         Proxy encryptedProxy = encryptedSettings.getValue().getProxies().get( 0 );
359         assertEquals( "proxy_password", secDispatcher.decrypt( encryptedProxy.getPassword() ) );
360 
361         File settingsSecurity = new File( System.getProperty( "user.home" ), ".m2/settings-security.xml" );
362         if ( settingsSecurity.exists() )
363         {
364             assertFalse( "server_passphrase".equals( encryptedServer.getPassphrase() ) );
365             assertFalse( "server_password".equals( encryptedServer.getPassword() ) );
366             assertFalse( "proxy_password".equals( encryptedProxy.getPassword() ) );
367         }
368     }
369 }