View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.testing;
20  
21  import java.io.File;
22  import java.io.InputStream;
23  import java.util.Map;
24  
25  import org.apache.maven.api.Session;
26  import org.apache.maven.execution.DefaultMavenExecutionRequest;
27  import org.apache.maven.execution.MavenExecutionRequest;
28  import org.apache.maven.execution.MavenSession;
29  import org.apache.maven.execution.MojoExecutionEvent;
30  import org.apache.maven.execution.MojoExecutionListener;
31  import org.apache.maven.execution.scope.internal.MojoExecutionScope;
32  import org.apache.maven.plugin.Mojo;
33  import org.apache.maven.plugin.MojoExecution;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.maven.project.ProjectBuilder;
36  import org.apache.maven.project.ProjectBuildingRequest;
37  import org.apache.maven.session.scope.internal.SessionScope;
38  import org.codehaus.plexus.ContainerConfiguration;
39  import org.codehaus.plexus.PlexusContainer;
40  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
41  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
42  import org.codehaus.plexus.configuration.PlexusConfiguration;
43  import org.codehaus.plexus.util.xml.Xpp3Dom;
44  import org.eclipse.aether.DefaultRepositorySystemSession;
45  import org.junit.Assert;
46  import org.junit.rules.TestRule;
47  import org.junit.runner.Description;
48  import org.junit.runners.model.Statement;
49  
50  /**
51   * {@link TestRule} for usage with Junit-4.10ff. This is just a wrapper for an embedded
52   * {@link AbstractMojoTestCase}, so all {@code protected} methods of the TestCase are
53   * exhibited as {@code public} in the rule. You may annotate single tests methods with
54   * {@link WithoutMojo} to prevent the rule from firing.
55   *
56   * @author Mirko Friedenhagen
57   * @since 2.2
58   */
59  public class MojoRule implements TestRule {
60      private final AbstractMojoTestCase testCase;
61  
62      public MojoRule() {
63          this(new AbstractMojoTestCase() {});
64      }
65  
66      public MojoRule(AbstractMojoTestCase testCase) {
67          this.testCase = testCase;
68      }
69  
70      /**
71       * May be overridden in the implementation to do stuff <em>after</em> the embedded test case
72       * is set up but <em>before</em> the current test is actually run.
73       *
74       * @throws Throwable
75       */
76      protected void before() throws Throwable {}
77  
78      /**
79       * May be overridden in the implementation to do stuff after the current test was run.
80       */
81      protected void after() {}
82  
83      public InputStream getPublicDescriptorStream() throws Exception {
84          return testCase.getPublicDescriptorStream();
85      }
86  
87      public String getPluginDescriptorPath() {
88          return testCase.getPluginDescriptorPath();
89      }
90  
91      public String getPluginDescriptorLocation() {
92          return testCase.getPluginDescriptorLocation();
93      }
94  
95      public void setupContainer() {
96          testCase.setupContainer();
97      }
98  
99      public ContainerConfiguration setupContainerConfiguration() {
100         return testCase.setupContainerConfiguration();
101     }
102 
103     public PlexusContainer getContainer() {
104         return testCase.getContainer();
105     }
106 
107     /**
108      * Lookup the mojo leveraging the subproject pom
109      *
110      * @param goal
111      * @param pluginPom
112      * @return a Mojo instance
113      * @throws Exception
114      */
115     public <T extends Mojo> T lookupMojo(String goal, String pluginPom) throws Exception {
116         return testCase.lookupMojo(goal, pluginPom);
117     }
118 
119     /**
120      * Lookup an empty mojo
121      *
122      * @param goal
123      * @param pluginPom
124      * @return a Mojo instance
125      * @throws Exception
126      */
127     public <T extends Mojo> T lookupEmptyMojo(String goal, String pluginPom) throws Exception {
128         return testCase.lookupEmptyMojo(goal, new File(pluginPom));
129     }
130 
131     /**
132      * Lookup the mojo leveraging the actual subprojects pom
133      *
134      * @param goal
135      * @param pom
136      * @return a Mojo instance
137      * @throws Exception
138      */
139     public <T extends Mojo> T lookupMojo(String goal, File pom) throws Exception {
140         return testCase.lookupMojo(goal, pom);
141     }
142 
143     /**
144      * Lookup the mojo leveraging the actual subprojects pom
145      *
146      * @param goal
147      * @param pom
148      * @return a Mojo instance
149      * @throws Exception
150      */
151     public <T extends Mojo> T lookupEmptyMojo(String goal, File pom) throws Exception {
152         return testCase.lookupEmptyMojo(goal, pom);
153     }
154 
155     public <T extends Mojo> T lookupMojo(
156             String groupId, String artifactId, String version, String goal, PlexusConfiguration pluginConfiguration)
157             throws Exception {
158         return testCase.lookupMojo(groupId, artifactId, version, goal, pluginConfiguration);
159     }
160 
161     public <T extends Mojo> T lookupConfiguredMojo(MavenProject project, String goal) throws Exception {
162         return testCase.lookupConfiguredMojo(project, goal);
163     }
164 
165     public <T extends Mojo> T lookupConfiguredMojo(MavenSession session, MojoExecution execution)
166             throws Exception, ComponentConfigurationException {
167         return testCase.lookupConfiguredMojo(session, execution);
168     }
169 
170     public MavenSession newMavenSession(MavenProject project) {
171         return testCase.newMavenSession(project);
172     }
173 
174     public MojoExecution newMojoExecution(String goal) {
175         return testCase.newMojoExecution(goal);
176     }
177 
178     public PlexusConfiguration extractPluginConfiguration(String artifactId, File pom) throws Exception {
179         return testCase.extractPluginConfiguration(artifactId, pom);
180     }
181 
182     public PlexusConfiguration extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
183         return testCase.extractPluginConfiguration(artifactId, pomDom);
184     }
185 
186     public <T extends Mojo> T configureMojo(T mojo, String artifactId, File pom) throws Exception {
187         return testCase.configureMojo(mojo, artifactId, pom);
188     }
189 
190     public <T extends Mojo> T configureMojo(T mojo, PlexusConfiguration pluginConfiguration) throws Exception {
191         return testCase.configureMojo(mojo, pluginConfiguration);
192     }
193 
194     /**
195      * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
196      *
197      * NOTE: the caller is responsible for casting to to what the desired type is.
198      *
199      * @param object
200      * @param variable
201      * @return object value of variable
202      * @throws IllegalArgumentException
203      */
204     public <T> T getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
205         return testCase.getVariableValueFromObject(object, variable);
206     }
207 
208     /**
209      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
210      *
211      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
212      *
213      * @param object
214      * @return map of variable names and values
215      */
216     public Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
217         return testCase.getVariablesAndValuesFromObject(object);
218     }
219 
220     /**
221      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
222      *
223      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
224      *
225      * @param clazz
226      * @param object
227      * @return map of variable names and values
228      */
229     public Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
230             throws IllegalAccessException {
231         return testCase.getVariablesAndValuesFromObject(clazz, object);
232     }
233 
234     /**
235      * Convenience method to set values to variables in objects that don't have setters
236      *
237      * @param object
238      * @param variable
239      * @param value
240      * @throws IllegalAccessException
241      */
242     public <T> void setVariableValueToObject(Object object, String variable, T value) throws IllegalAccessException {
243         testCase.setVariableValueToObject(object, variable, value);
244     }
245 
246     @Override
247     public Statement apply(final Statement base, Description description) {
248         if (description.getAnnotation(WithoutMojo.class) != null) // skip.
249         {
250             return base;
251         }
252         return new Statement() {
253             @Override
254             public void evaluate() throws Throwable {
255                 testCase.setUp();
256                 before();
257                 try {
258                     base.evaluate();
259                 } finally {
260                     after();
261                 }
262             }
263         };
264     }
265 
266     /**
267      * @since 3.1.0
268      */
269     public MavenProject readMavenProject(File basedir) throws Exception {
270         File pom = new File(basedir, "pom.xml");
271         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
272         request.setBaseDirectory(basedir);
273         ProjectBuildingRequest configuration = request.getProjectBuildingRequest();
274         configuration.setRepositorySession(new DefaultRepositorySystemSession());
275         MavenProject project =
276                 lookup(ProjectBuilder.class).build(pom, configuration).getProject();
277         Assert.assertNotNull(project);
278         return project;
279     }
280 
281     /**
282      * @since 3.1.0
283      */
284     public void executeMojo(File basedir, String goal) throws Exception {
285         MavenProject project = readMavenProject(basedir);
286         MavenSession session = newMavenSession(project);
287         MojoExecution execution = newMojoExecution(goal);
288         executeMojo(session, project, execution);
289     }
290 
291     /**
292      * @since 3.1.0
293      */
294     public <T extends Mojo> T lookupConfiguredMojo(File basedir, String goal)
295             throws Exception, ComponentConfigurationException {
296         MavenProject project = readMavenProject(basedir);
297         MavenSession session = newMavenSession(project);
298         MojoExecution execution = newMojoExecution(goal);
299         return lookupConfiguredMojo(session, execution);
300     }
301 
302     /**
303      * @since 3.1.0
304      */
305     public final <T> T lookup(final Class<T> role) throws ComponentLookupException {
306         return getContainer().lookup(role);
307     }
308 
309     /**
310      * @since 3.2.0
311      */
312     public void executeMojo(MavenProject project, String goal, Xpp3Dom... parameters) throws Exception {
313         MavenSession session = newMavenSession(project);
314         executeMojo(session, project, goal, parameters);
315     }
316 
317     /**
318      * @since 3.2.0
319      */
320     public void executeMojo(MavenSession session, MavenProject project, String goal, Xpp3Dom... parameters)
321             throws Exception {
322         MojoExecution execution = newMojoExecution(goal);
323         if (parameters != null) {
324             Xpp3Dom configuration = execution.getConfiguration();
325             for (Xpp3Dom parameter : parameters) {
326                 configuration.addChild(parameter);
327             }
328         }
329         executeMojo(session, project, execution);
330     }
331 
332     /**
333      * @since 3.2.0
334      */
335     public void executeMojo(MavenSession session, MavenProject project, MojoExecution execution) throws Exception {
336         SessionScope sessionScope = lookup(SessionScope.class);
337         try {
338             sessionScope.enter();
339             sessionScope.seed(MavenSession.class, session);
340             sessionScope.seed(Session.class, session.getSession());
341 
342             MojoExecutionScope executionScope = lookup(MojoExecutionScope.class);
343             try {
344                 executionScope.enter();
345 
346                 executionScope.seed(MavenProject.class, project);
347                 executionScope.seed(MojoExecution.class, execution);
348 
349                 Mojo mojo = lookupConfiguredMojo(session, execution);
350                 mojo.execute();
351 
352                 MojoExecutionEvent event = new MojoExecutionEvent(session, project, execution, mojo);
353                 for (MojoExecutionListener listener : getContainer().lookupList(MojoExecutionListener.class)) {
354                     listener.afterMojoExecutionSuccess(event);
355                 }
356             } finally {
357                 executionScope.exit();
358             }
359         } finally {
360             sessionScope.exit();
361         }
362     }
363 }