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}