001package org.apache.maven.script.ant;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import static org.junit.Assert.assertThat;
023import static org.junit.Assert.fail;
024import static org.mockito.Mockito.atLeastOnce;
025import static org.mockito.Mockito.mock;
026import static org.mockito.Mockito.verify;
027import static org.mockito.Mockito.when;
028import static org.hamcrest.CoreMatchers.endsWith;
029import static org.hamcrest.CoreMatchers.startsWith;
030
031import java.io.ByteArrayOutputStream;
032import java.io.File;
033import java.io.IOException;
034import java.io.InputStreamReader;
035import java.io.PrintStream;
036import java.io.Reader;
037import java.net.URISyntaxException;
038import java.net.URL;
039import java.nio.file.Paths;
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.HashMap;
043import java.util.List;
044import java.util.Map;
045
046import org.apache.maven.artifact.Artifact;
047import org.apache.maven.execution.MavenSession;
048import org.apache.maven.model.Build;
049import org.apache.maven.model.Model;
050import org.apache.maven.plugin.MojoExecution;
051import org.apache.maven.plugin.MojoExecutionException;
052import org.apache.maven.plugin.descriptor.MojoDescriptor;
053import org.apache.maven.plugin.descriptor.PluginDescriptor;
054import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
055import org.apache.maven.project.MavenProject;
056import org.apache.maven.project.path.PathTranslator;
057import org.apache.tools.ant.BuildEvent;
058import org.apache.tools.ant.BuildListener;
059import org.codehaus.plexus.archiver.ArchiverException;
060import org.codehaus.plexus.archiver.jar.JarArchiver;
061import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
062import org.codehaus.plexus.component.factory.ComponentInstantiationException;
063import org.codehaus.plexus.component.factory.ant.AntScriptInvoker;
064import org.codehaus.plexus.component.repository.ComponentRequirement;
065import org.codehaus.plexus.configuration.PlexusConfigurationException;
066import org.codehaus.plexus.logging.Logger;
067import org.codehaus.plexus.logging.console.ConsoleLogger;
068import org.junit.Before;
069import org.junit.Test;
070import org.mockito.ArgumentCaptor;
071
072public class AntMojoWrapperTest
073{
074    
075    private BuildListener buildListener;
076
077    @Before
078    public void setUp() 
079    {
080        buildListener = mock( BuildListener.class );
081    }
082    
083    @Test
084    public void test2xStylePlugin()
085        throws PlexusConfigurationException, IOException, ComponentInstantiationException, MojoExecutionException,
086        ComponentConfigurationException, ArchiverException, URISyntaxException
087    {
088        String pluginXml = "META-INF/maven/plugin-2.1.xml";
089
090        List<String> messages = run( pluginXml, true );
091
092        assertPresence( messages, "Unpacked Ant build scripts (in Maven build directory).", false );
093        assertPresence( messages, "Maven parameter expression evaluator for Ant properties.", false );
094        assertPresence( messages, "Maven standard project-based classpath references.", false );
095        assertPresence( messages, "Maven standard plugin-based classpath references.", false );
096        assertPresence( messages,
097                        "Maven project, session, mojo-execution, or path-translation parameter information is", false );
098        assertPresence( messages, "maven-script-ant < 2.1.0, or used maven-plugin-tools-ant < 2.2 during release",
099                        false );
100
101        ArgumentCaptor<BuildEvent> buildEvent = ArgumentCaptor.forClass(BuildEvent.class);
102        verify( buildListener, atLeastOnce() ).messageLogged( buildEvent.capture() );
103
104        // last message
105        assertThat( buildEvent.getValue().getMessage(), startsWith( "plugin classpath is: " ) );
106        assertThat( buildEvent.getValue().getMessage(), endsWith( ".test.jar" ) );
107    }
108
109    @Test
110    public void test20StylePlugin()
111        throws PlexusConfigurationException, IOException, ComponentInstantiationException, MojoExecutionException,
112        ComponentConfigurationException, ArchiverException, URISyntaxException
113    {
114        String pluginXml = "META-INF/maven/plugin-2.0.xml";
115
116        List<String> messages = run( pluginXml, false );
117
118        assertPresence( messages, "Unpacked Ant build scripts (in Maven build directory).", true );
119        assertPresence( messages, "Maven parameter expression evaluator for Ant properties.", true );
120        assertPresence( messages, "Maven standard project-based classpath references.", true );
121        assertPresence( messages, "Maven standard plugin-based classpath references.", true );
122        assertPresence( messages,
123                        "Maven project, session, mojo-execution, or path-translation parameter information is", true );
124        assertPresence( messages, "maven-script-ant < 2.1.0, or used maven-plugin-tools-ant < 2.2 during release", true );
125
126        ArgumentCaptor<BuildEvent> buildEvent = ArgumentCaptor.forClass(BuildEvent.class);
127        verify( buildListener, atLeastOnce() ).messageLogged( buildEvent.capture() );
128
129        // last message
130        assertThat( buildEvent.getValue().getMessage(), startsWith( "plugin classpath is: " ) );
131        assertThat( buildEvent.getValue().getMessage(), endsWith( "path-is-missing" ) );
132    }
133
134    private void assertPresence( List<String> messages, String test, boolean shouldBePresent )
135    {
136        for ( String message : messages )
137        {
138            if ( message.contains( test ) )
139            {
140                if ( !shouldBePresent )
141                {
142                    fail( "Test string: '" + test + "' was found in output, but SHOULD NOT BE THERE." );
143                }
144                return;
145            }
146        }
147
148        if ( shouldBePresent )
149        {
150            fail( "Test string: '" + test + "' was NOT found in output, but SHOULD BE THERE." );
151        }
152    }
153
154    private List<String> run( String pluginXml, boolean includeImplied )
155        throws PlexusConfigurationException, IOException, ComponentInstantiationException, MojoExecutionException,
156        ComponentConfigurationException, ArchiverException, URISyntaxException
157    {
158        StackTraceElement stack = new Throwable().getStackTrace()[1];
159        System.out.println( "\n\nRunning: " + stack.getMethodName() + "\n\n" );
160
161        URL resource = Thread.currentThread().getContextClassLoader().getResource( pluginXml );
162
163        if ( resource == null )
164        {
165            fail( "plugin descriptor not found: '" + pluginXml + "'." );
166        }
167
168        PluginDescriptor pd;
169        try ( Reader reader = new InputStreamReader( resource.openStream() ) )
170        {
171            pd = new PluginDescriptorBuilder().build( reader, pluginXml );
172        }
173
174        Map<String, Object> config = new HashMap<>();
175        config.put( "basedir", new File( "." ).getAbsoluteFile() );
176        config.put( "messageLevel", "info" );
177
178        MojoDescriptor md = pd.getMojo( "test" );
179
180        AntMojoWrapper wrapper =
181            new AntMojoWrapper( new AntScriptInvoker( md, Thread.currentThread().getContextClassLoader() ) );
182
183        wrapper.enableLogging( new ConsoleLogger( Logger.LEVEL_DEBUG, "test" ) );
184
185        Artifact artifact = mock( Artifact.class );
186        PathTranslator pt = mock( PathTranslator.class );
187
188        if ( includeImplied )
189        {
190            File pluginXmlFile = Paths.get( resource.toURI() ).toFile();
191
192            File jarFile = File.createTempFile( "AntMojoWrapperTest.", ".test.jar" );
193            jarFile.deleteOnExit();
194
195            JarArchiver archiver = new JarArchiver();
196            archiver.enableLogging( new ConsoleLogger( Logger.LEVEL_ERROR, "archiver" ) );
197            archiver.setDestFile( jarFile );
198            archiver.addFile( pluginXmlFile, pluginXml );
199            archiver.createArchive();
200
201            when( artifact.getFile() ).thenReturn( jarFile );
202
203            Model model = new Model();
204
205            Build build = new Build();
206            build.setDirectory( "target" );
207
208            model.setBuild( build );
209
210            MavenProject project = new MavenProject( model );
211            project.setFile( new File( "pom.xml" ).getAbsoluteFile() );
212
213            pd.setPluginArtifact( artifact );
214            pd.setArtifacts( Collections.singletonList( artifact ) );
215
216            config.put( "project", project );
217            config.put( "session", new MavenSession( null, null, null, null, null, null, null, null, null, null ) );
218            config.put( "mojoExecution", new MojoExecution( md ) );
219
220            ComponentRequirement cr = new ComponentRequirement();
221            cr.setRole( PathTranslator.class.getName() );
222
223            wrapper.addComponentRequirement( cr, pt );
224        }
225
226        wrapper.setComponentConfiguration( config );
227
228        TestBuildListener tbl = new TestBuildListener();
229        
230        wrapper.getAntProject().addBuildListener( buildListener );
231        
232        PrintStream oldOut = System.out;
233        
234        ByteArrayOutputStream baos = new ByteArrayOutputStream();
235        try
236        {
237            System.setOut( new PrintStream( baos ) );
238
239            wrapper.execute();
240        }
241        finally
242        {
243            System.setOut( oldOut );
244        }
245
246        System.out.println( "\n\n" + stack.getMethodName() + " executed; verifying...\n\n" );
247
248        List<String> messages = new ArrayList<>();
249        if ( !tbl.messages.isEmpty() )
250        {
251            messages.addAll( tbl.messages );
252        }
253        
254        messages.add( new String( baos.toByteArray() ) );
255        
256        return messages;
257    }
258
259    private static final class TestBuildListener
260        implements BuildListener
261    {
262        private List<String> messages = new ArrayList<>();
263
264        public void buildFinished( BuildEvent arg0 )
265        {
266        }
267
268        public void buildStarted( BuildEvent arg0 )
269        {
270        }
271
272        public void messageLogged( BuildEvent event )
273        {
274            messages.add( event.getMessage() );
275        }
276
277        public void targetFinished( BuildEvent arg0 )
278        {
279        }
280
281        public void targetStarted( BuildEvent arg0 )
282        {
283        }
284
285        public void taskFinished( BuildEvent arg0 )
286        {
287        }
288
289        public void taskStarted( BuildEvent arg0 )
290        {
291        }
292    }
293}