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.dependency.exclusion;
20  
21  import java.io.File;
22  import java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.List;
29  
30  import org.apache.maven.RepositoryUtils;
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.model.Dependency;
34  import org.apache.maven.model.Exclusion;
35  import org.apache.maven.model.InputLocation;
36  import org.apache.maven.model.InputSource;
37  import org.apache.maven.plugin.LegacySupport;
38  import org.apache.maven.plugin.MojoExecutionException;
39  import org.apache.maven.plugin.logging.Log;
40  import org.apache.maven.plugins.dependency.AbstractDependencyMojoTestCase;
41  import org.apache.maven.plugins.dependency.testUtils.stubs.DependencyProjectStub;
42  import org.apache.maven.plugins.dependency.utils.ResolverUtil;
43  import org.apache.maven.project.MavenProject;
44  
45  import static org.assertj.core.api.Assertions.assertThat;
46  import static org.assertj.core.api.Assertions.assertThatCode;
47  import static org.assertj.core.api.Assertions.assertThatThrownBy;
48  import static org.mockito.ArgumentMatchers.any;
49  import static org.mockito.Mockito.mock;
50  import static org.mockito.Mockito.when;
51  
52  public class AnalyzeExclusionsMojoTest extends AbstractDependencyMojoTestCase {
53  
54      private AnalyzeExclusionsMojo mojo;
55  
56      private MavenProject project;
57  
58      private TestLog testLog;
59  
60      private ResolverUtil resolverUtil;
61  
62      @Override
63      public void setUp() throws Exception {
64          super.setUp("analyze-exclusions", true, false);
65  
66          project = new DependencyProjectStub();
67          project.setName("projectName");
68          project.setGroupId("testGroupId");
69          project.setArtifactId("testArtifactId");
70          project.setVersion("1.0.0");
71  
72          getContainer().addComponent(project, MavenProject.class.getName());
73  
74          MavenSession session = newMavenSession(project);
75          getContainer().addComponent(session, MavenSession.class.getName());
76  
77          resolverUtil = mock(ResolverUtil.class);
78          getContainer().addComponent(resolverUtil, ResolverUtil.class.getName());
79  
80          File testPom = new File(getBasedir(), "target/test-classes/unit/analyze-exclusions/plugin-config.xml");
81          mojo = (AnalyzeExclusionsMojo) lookupMojo("analyze-exclusions", testPom);
82          assertNotNull(mojo);
83  
84          LegacySupport legacySupport = lookup(LegacySupport.class);
85          legacySupport.setSession(session);
86          installLocalRepository(legacySupport);
87  
88          testLog = new TestLog();
89          mojo.setLog(testLog);
90      }
91  
92      public void testShallThrowExceptionWhenFailOnWarning() throws Exception {
93          List<Dependency> dependencies = new ArrayList<>();
94          Dependency withInvalidExclusion = dependency("a", "b");
95          withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
96          dependencies.add(withInvalidExclusion);
97          project.setDependencies(dependencies);
98          Artifact artifact = stubFactory.createArtifact("a", "b", "1.0");
99          project.setArtifacts(new HashSet<>(Collections.singletonList(artifact)));
100         setVariableValueToObject(mojo, "exclusionFail", true);
101 
102         assertThatThrownBy(() -> mojo.execute())
103                 .isInstanceOf(MojoExecutionException.class)
104                 .hasMessageContaining("Invalid exclusions found");
105 
106         assertThat(testLog.getContent()).startsWith("[error]");
107     }
108 
109     public void testShallLogWarningWhenFailOnWarningIsFalse() throws Exception {
110         List<Dependency> dependencies = new ArrayList<>();
111         Dependency withInvalidExclusion = dependency("a", "b");
112         withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
113         dependencies.add(withInvalidExclusion);
114         project.setDependencies(dependencies);
115         Artifact artifact = stubFactory.createArtifact("a", "b", "1.0");
116         project.setArtifacts(new HashSet<>(Collections.singletonList(artifact)));
117         setVariableValueToObject(mojo, "exclusionFail", false);
118 
119         mojo.execute();
120 
121         assertThat(testLog.getContent()).startsWith("[warn]");
122     }
123 
124     public void testShallExitWithoutAnalyzeWhenNoDependencyHasExclusion() throws Exception {
125         List<Dependency> dependencies = new ArrayList<>();
126         dependencies.add(dependency("a", "c"));
127         project.setDependencies(dependencies);
128         mojo.execute();
129         assertThat(testLog.getContent()).startsWith("[debug] No dependencies defined with exclusions - exiting");
130     }
131 
132     public void testShallNotReportInvalidExclusionForWildcardGroupIdAndArtifactId() throws Exception {
133         Dependency dependencyWithWildcardExclusion = dependency("a", "b");
134         dependencyWithWildcardExclusion.addExclusion(exclusion("*", "*"));
135         project.setDependencies(Collections.singletonList(dependencyWithWildcardExclusion));
136         Artifact artifact = stubFactory.createArtifact("a", "b", "1.0");
137         project.setArtifacts(new HashSet<>(Collections.singletonList(artifact)));
138 
139         when(resolverUtil.collectDependencies(any()))
140                 .thenReturn(Collections.singletonList(new org.eclipse.aether.graph.Dependency(
141                         RepositoryUtils.toArtifact(stubFactory.createArtifact("whatever", "ok", "1.0")), "")));
142 
143         mojo.execute();
144 
145         assertThat(testLog.getContent()).doesNotContain("[warn]     a:b:", "[warn]         - *:*");
146     }
147 
148     public void testCanResolveMultipleArtifactsWithEqualGroupIdAndArtifactId() throws Exception {
149         Dependency dependency1 = dependency("a", "b");
150         Dependency dependency2 = dependency("a", "b", "compile", "native");
151         dependency1.addExclusion(exclusion("c", "d"));
152         dependency2.addExclusion(exclusion("c", "d"));
153         project.setDependencies(Arrays.asList(dependency1, dependency2));
154         Artifact artifact1 = stubFactory.createArtifact("a", "b", "1.0");
155         Artifact artifact2 = stubFactory.createArtifact("a", "b", "1.0", "compile", "jar", "native");
156         project.setArtifacts(new HashSet<>(Arrays.asList(artifact1, artifact2)));
157 
158         assertThatCode(() -> mojo.execute()).doesNotThrowAnyException();
159     }
160 
161     public void testShallNotLogWhenExclusionIsValid() throws Exception {
162         List<Dependency> dependencies = new ArrayList<>();
163         Dependency dependency = dependency("a", "b");
164         dependency.addExclusion(exclusion("ok", "ok"));
165         dependencies.add(dependency);
166         project.setDependencies(dependencies);
167         Artifact artifact = stubFactory.createArtifact("a", "b", "1.0");
168 
169         project.setArtifacts(new HashSet<>(Collections.singletonList(artifact)));
170         setVariableValueToObject(mojo, "exclusionFail", true);
171 
172         when(resolverUtil.collectDependencies(any()))
173                 .thenReturn(Collections.singletonList(new org.eclipse.aether.graph.Dependency(
174                         RepositoryUtils.toArtifact(stubFactory.createArtifact("ok", "ok", "1.0")), "")));
175 
176         assertThatCode(() -> mojo.execute()).doesNotThrowAnyException();
177     }
178 
179     public void testThatLogContainProjectName() throws Exception {
180         List<Dependency> dependencies = new ArrayList<>();
181         Dependency withInvalidExclusion = dependency("a", "b");
182         withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
183         dependencies.add(withInvalidExclusion);
184         project.setDependencies(dependencies);
185         Artifact artifact = stubFactory.createArtifact("a", "b", "1.0");
186         project.setArtifacts(new HashSet<>(Collections.singletonList(artifact)));
187 
188         mojo.execute();
189 
190         assertThat(testLog.getContent()).contains("[warn] projectName defines following unnecessary excludes");
191     }
192 
193     private Dependency dependency(String groupId, String artifactId) {
194         Dependency dependency = new Dependency();
195         dependency.setGroupId(groupId);
196         dependency.setArtifactId(artifactId);
197         dependency.setVersion("1.0");
198         dependency.setScope("compile");
199         dependency.setType("jar");
200         dependency.setClassifier("");
201         dependency.setLocation("", new InputLocation(1, 1));
202         return dependency;
203     }
204 
205     private Dependency dependency(String groupId, String artifactId, String scope, String classifier) {
206         Dependency dependency = new Dependency();
207         dependency.setGroupId(groupId);
208         dependency.setArtifactId(artifactId);
209         dependency.setVersion("1.0");
210         dependency.setScope(scope);
211         dependency.setType("jar");
212         dependency.setClassifier(classifier);
213         dependency.setLocation("", new InputLocation(1, 1));
214         return dependency;
215     }
216 
217     private Exclusion exclusion(String groupId, String artifactId) {
218         Exclusion exclusion = new Exclusion();
219         exclusion.setGroupId(groupId);
220         exclusion.setArtifactId(artifactId);
221         InputSource inputSource = new InputSource();
222         inputSource.setModelId("testGroupId:testArtifactId:1.0.0");
223         exclusion.setLocation("", new InputLocation(1, 1, inputSource));
224         return exclusion;
225     }
226 
227     static class TestLog implements Log {
228         StringBuilder sb = new StringBuilder();
229 
230         /**
231          * {@inheritDoc}
232          */
233         public void debug(CharSequence content) {
234             print("debug", content);
235         }
236 
237         /**
238          * {@inheritDoc}
239          */
240         public void debug(CharSequence content, Throwable error) {
241             print("debug", content, error);
242         }
243 
244         /**
245          * {@inheritDoc}
246          */
247         public void debug(Throwable error) {
248             print("debug", error);
249         }
250 
251         /**
252          * {@inheritDoc}
253          */
254         public void info(CharSequence content) {
255             print("info", content);
256         }
257 
258         /**
259          * {@inheritDoc}
260          */
261         public void info(CharSequence content, Throwable error) {
262             print("info", content, error);
263         }
264 
265         /**
266          * {@inheritDoc}
267          */
268         public void info(Throwable error) {
269             print("info", error);
270         }
271 
272         /**
273          * {@inheritDoc}
274          */
275         public void warn(CharSequence content) {
276             print("warn", content);
277         }
278 
279         /**
280          * {@inheritDoc}
281          */
282         public void warn(CharSequence content, Throwable error) {
283             print("warn", content, error);
284         }
285 
286         /**
287          * {@inheritDoc}
288          */
289         public void warn(Throwable error) {
290             print("warn", error);
291         }
292 
293         /**
294          * {@inheritDoc}
295          */
296         public void error(CharSequence content) {
297             print("error", content);
298         }
299 
300         /**
301          * {@inheritDoc}
302          */
303         public void error(CharSequence content, Throwable error) {
304             StringWriter sWriter = new StringWriter();
305             PrintWriter pWriter = new PrintWriter(sWriter);
306 
307             error.printStackTrace(pWriter);
308 
309             System.err.println(
310                     "[error] " + content.toString() + System.lineSeparator() + System.lineSeparator() + sWriter);
311         }
312 
313         /**
314          * @see org.apache.maven.plugin.logging.Log#error(java.lang.Throwable)
315          */
316         public void error(Throwable error) {
317             StringWriter sWriter = new StringWriter();
318             PrintWriter pWriter = new PrintWriter(sWriter);
319 
320             error.printStackTrace(pWriter);
321 
322             System.err.println("[error] " + sWriter);
323         }
324 
325         /**
326          * @see org.apache.maven.plugin.logging.Log#isDebugEnabled()
327          */
328         public boolean isDebugEnabled() {
329             // TODO: Not sure how best to set these for this implementation...
330             return false;
331         }
332 
333         /**
334          * @see org.apache.maven.plugin.logging.Log#isInfoEnabled()
335          */
336         public boolean isInfoEnabled() {
337             return true;
338         }
339 
340         /**
341          * @see org.apache.maven.plugin.logging.Log#isWarnEnabled()
342          */
343         public boolean isWarnEnabled() {
344             return true;
345         }
346 
347         /**
348          * @see org.apache.maven.plugin.logging.Log#isErrorEnabled()
349          */
350         public boolean isErrorEnabled() {
351             return true;
352         }
353 
354         private void print(String prefix, CharSequence content) {
355             sb.append("[")
356                     .append(prefix)
357                     .append("] ")
358                     .append(content.toString())
359                     .append(System.lineSeparator());
360         }
361 
362         private void print(String prefix, Throwable error) {
363             StringWriter sWriter = new StringWriter();
364             PrintWriter pWriter = new PrintWriter(sWriter);
365 
366             error.printStackTrace(pWriter);
367 
368             sb.append("[").append(prefix).append("] ").append(sWriter).append(System.lineSeparator());
369         }
370 
371         private void print(String prefix, CharSequence content, Throwable error) {
372             StringWriter sWriter = new StringWriter();
373             PrintWriter pWriter = new PrintWriter(sWriter);
374 
375             error.printStackTrace(pWriter);
376 
377             sb.append("[")
378                     .append(prefix)
379                     .append("] ")
380                     .append(content.toString())
381                     .append(System.lineSeparator())
382                     .append(System.lineSeparator());
383             sb.append(sWriter).append(System.lineSeparator());
384         }
385 
386         protected String getContent() {
387             return sb.toString();
388         }
389     }
390 }