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.plugins.shade.mojo;
20  
21  import java.io.File;
22  import java.lang.reflect.Field;
23  import java.lang.reflect.Method;
24  import java.net.URL;
25  import java.net.URLClassLoader;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Set;
32  
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.artifact.DefaultArtifact;
35  import org.apache.maven.artifact.handler.ArtifactHandler;
36  import org.apache.maven.artifact.versioning.VersionRange;
37  import org.apache.maven.execution.MavenExecutionRequest;
38  import org.apache.maven.execution.MavenExecutionResult;
39  import org.apache.maven.execution.MavenSession;
40  import org.apache.maven.plugin.testing.AbstractMojoTestCase;
41  import org.apache.maven.plugins.shade.ShadeRequest;
42  import org.apache.maven.plugins.shade.Shader;
43  import org.apache.maven.plugins.shade.filter.Filter;
44  import org.apache.maven.plugins.shade.relocation.Relocator;
45  import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
46  import org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer;
47  import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer;
48  import org.apache.maven.plugins.shade.resource.ResourceTransformer;
49  import org.apache.maven.project.MavenProject;
50  import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
51  import org.codehaus.plexus.ContainerConfiguration;
52  import org.codehaus.plexus.PlexusConstants;
53  import org.eclipse.aether.DefaultRepositorySystemSession;
54  import org.eclipse.aether.RepositorySystem;
55  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
56  import org.eclipse.aether.repository.LocalRepository;
57  import org.eclipse.aether.resolution.ArtifactRequest;
58  import org.eclipse.aether.resolution.ArtifactResult;
59  
60  import static java.util.Arrays.asList;
61  import static java.util.Collections.singletonList;
62  import static org.mockito.ArgumentMatchers.any;
63  import static org.mockito.ArgumentMatchers.eq;
64  import static org.mockito.Mockito.mock;
65  import static org.mockito.Mockito.when;
66  
67  /**
68   * @author Jason van Zyl
69   * @author Mauro Talevi
70   */
71  public class ShadeMojoTest extends AbstractMojoTestCase {
72      @Override
73      protected void customizeContainerConfiguration(final ContainerConfiguration configuration) {
74          configuration.setClassPathScanning(PlexusConstants.SCANNING_INDEX);
75      }
76  
77      public void testManifestTransformerSelection() throws Exception {
78          final ShadeMojo mojo = new ShadeMojo();
79          final Method m = ShadeMojo.class.getDeclaredMethod("toResourceTransformers", String.class, List.class);
80          m.setAccessible(true);
81  
82          final ManifestResourceTransformer defaultTfr = new ManifestResourceTransformer() {
83              @Override
84              public String toString() // when test fails junit does a toString so easier to read errors this way
85                      {
86                  return "default";
87              }
88          };
89          final ManifestResourceTransformer testsTfr1 = new ManifestResourceTransformer() {
90              @Override
91              public String toString() {
92                  return "t1";
93              }
94          };
95          testsTfr1.setForShade("tests");
96          final ManifestResourceTransformer testsTfr2 = new ManifestResourceTransformer() {
97              @Override
98              public String toString() {
99                  return "t2";
100             }
101         };
102         testsTfr2.setForShade("tests");
103 
104         assertEquals(singletonList(defaultTfr), m.invoke(mojo, "jar", asList(defaultTfr, testsTfr1, testsTfr2)));
105         assertEquals(asList(testsTfr1, testsTfr2), m.invoke(mojo, "tests", asList(defaultTfr, testsTfr1, testsTfr2)));
106         assertEquals(asList(testsTfr1, testsTfr2), m.invoke(mojo, "tests", asList(testsTfr1, defaultTfr, testsTfr2)));
107         assertEquals(asList(testsTfr1, testsTfr2), m.invoke(mojo, "tests", asList(testsTfr1, testsTfr2, defaultTfr)));
108     }
109 
110     public void testShaderWithDefaultShadedPattern() throws Exception {
111         shaderWithPattern(null, new File("target/foo-default.jar"));
112     }
113 
114     public void testShaderWithCustomShadedPattern() throws Exception {
115         shaderWithPattern("org/shaded/plexus/util", new File("target/foo-custom.jar"));
116     }
117 
118     public void testShaderWithExclusions() throws Exception {
119         File jarFile = new File(getBasedir(), "target/unit/foo-bar.jar");
120 
121         Shader s = lookup(Shader.class);
122 
123         Set<File> set = new LinkedHashSet<>();
124         set.add(new File(getBasedir(), "src/test/jars/test-artifact-1.0-SNAPSHOT.jar"));
125 
126         List<Relocator> relocators = new ArrayList<>();
127         relocators.add(new SimpleRelocator(
128                 "org.codehaus.plexus.util",
129                 "hidden",
130                 null,
131                 Arrays.asList("org.codehaus.plexus.util.xml.Xpp3Dom", "org.codehaus.plexus.util.xml.pull.*")));
132 
133         List<ResourceTransformer> resourceTransformers = new ArrayList<>();
134 
135         List<Filter> filters = new ArrayList<>();
136 
137         ShadeRequest shadeRequest = new ShadeRequest();
138         shadeRequest.setJars(set);
139         shadeRequest.setUberJar(jarFile);
140         shadeRequest.setFilters(filters);
141         shadeRequest.setRelocators(relocators);
142         shadeRequest.setResourceTransformers(resourceTransformers);
143 
144         s.shade(shadeRequest);
145 
146         try (URLClassLoader cl = new URLClassLoader(new URL[] {jarFile.toURI().toURL()})) {
147             Class<?> c = cl.loadClass("org.apache.maven.plugins.shade.Lib");
148 
149             Field field = c.getDeclaredField("CLASS_REALM_PACKAGE_IMPORT");
150             assertEquals("org.codehaus.plexus.util.xml.pull", field.get(null));
151 
152             Method method = c.getDeclaredMethod("getClassRealmPackageImport");
153             assertEquals("org.codehaus.plexus.util.xml.pull", method.invoke(null));
154         }
155     }
156 
157     /**
158      * Tests if a Filter is installed correctly, also if createSourcesJar is set to true.
159      *
160      * @throws Exception
161      */
162     public void testShadeWithFilter() throws Exception {
163         // create and configure MavenProject
164         MavenProject project = new MavenProject();
165         ArtifactHandler artifactHandler = lookup(ArtifactHandler.class);
166         Artifact artifact = new DefaultArtifact(
167                 "org.apache.myfaces.core",
168                 "myfaces-impl",
169                 VersionRange.createFromVersion("2.0.1-SNAPSHOT"),
170                 "compile",
171                 "jar",
172                 null,
173                 artifactHandler);
174         artifact.setFile(new File("myfaces-impl-2.0.1-SNAPSHOT.jar"));
175         project.setArtifact(artifact);
176 
177         ShadeMojo mojo = (ShadeMojo) lookupConfiguredMojo(project, "shade");
178 
179         DefaultRepositorySystemSession repositorySystemSession = MavenRepositorySystemUtils.newSession();
180         repositorySystemSession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
181                 .newInstance(repositorySystemSession, new LocalRepository(new File("target/local-repo/"))));
182         MavenSession mavenSession = new MavenSession(
183                 getContainer(),
184                 repositorySystemSession,
185                 mock(MavenExecutionRequest.class),
186                 mock(MavenExecutionResult.class));
187 
188         setVariableValueToObject(mojo, "session", mavenSession);
189 
190         // set createSourcesJar = true
191         setVariableValueToObject(mojo, "createSourcesJar", true);
192 
193         RepositorySystem repositorySystem = mock(RepositorySystem.class);
194         setVariableValueToObject(mojo, "repositorySystem", repositorySystem);
195 
196         ArtifactResult artifactResult = new ArtifactResult(
197                 new ArtifactRequest(mock(org.eclipse.aether.artifact.Artifact.class), Collections.emptyList(), ""));
198         org.eclipse.aether.artifact.Artifact result = new org.eclipse.aether.artifact.DefaultArtifact(
199                         "org.apache.myfaces.core:myfaces-impl:jar:sources:2.0.1-SNAPSHOT")
200                 .setFile(new File("myfaces-impl-2.0.1-SNAPSHOT-sources.jar"));
201         artifactResult.setArtifact(result);
202         when(repositorySystem.resolveArtifact(eq(mavenSession.getRepositorySession()), any(ArtifactRequest.class)))
203                 .thenReturn(artifactResult);
204 
205         // create and configure the ArchiveFilter
206         ArchiveFilter archiveFilter = new ArchiveFilter();
207         Field archiveFilterArtifact = ArchiveFilter.class.getDeclaredField("artifact");
208         archiveFilterArtifact.setAccessible(true);
209         archiveFilterArtifact.set(archiveFilter, "org.apache.myfaces.core:myfaces-impl");
210 
211         // add ArchiveFilter to mojo
212         Field filtersField = ShadeMojo.class.getDeclaredField("filters");
213         filtersField.setAccessible(true);
214         filtersField.set(mojo, new ArchiveFilter[] {archiveFilter});
215 
216         // invoke getFilters()
217         Method getFilters = ShadeMojo.class.getDeclaredMethod("getFilters");
218         getFilters.setAccessible(true);
219         List<Filter> filters = (List<Filter>) getFilters.invoke(mojo);
220 
221         // assertions - there must be one filter
222         assertEquals(1, filters.size());
223 
224         // the filter must be able to filter the binary and the sources jar
225         Filter filter = filters.get(0);
226         assertTrue(filter.canFilter(new File("myfaces-impl-2.0.1-SNAPSHOT.jar"))); // binary jar
227         assertTrue(filter.canFilter(new File("myfaces-impl-2.0.1-SNAPSHOT-sources.jar"))); // sources jar
228     }
229 
230     public void shaderWithPattern(String shadedPattern, File jar) throws Exception {
231         Shader s = lookup(Shader.class);
232 
233         Set<File> set = new LinkedHashSet<>();
234 
235         set.add(new File(getBasedir(), "src/test/jars/test-project-1.0-SNAPSHOT.jar"));
236 
237         set.add(new File(getBasedir(), "src/test/jars/plexus-utils-1.4.1.jar"));
238 
239         List<Relocator> relocators = new ArrayList<>();
240 
241         relocators.add(new SimpleRelocator(
242                 "org/codehaus/plexus/util",
243                 shadedPattern,
244                 null,
245                 Arrays.asList("org/codehaus/plexus/util/xml/Xpp3Dom", "org/codehaus/plexus/util/xml/pull.*")));
246 
247         List<ResourceTransformer> resourceTransformers = new ArrayList<>();
248 
249         resourceTransformers.add(new ComponentsXmlResourceTransformer());
250 
251         List<Filter> filters = new ArrayList<>();
252 
253         ShadeRequest shadeRequest = new ShadeRequest();
254         shadeRequest.setJars(set);
255         shadeRequest.setUberJar(jar);
256         shadeRequest.setFilters(filters);
257         shadeRequest.setRelocators(relocators);
258         shadeRequest.setResourceTransformers(resourceTransformers);
259 
260         s.shade(shadeRequest);
261     }
262 }