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 javax.inject.Inject;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import org.apache.maven.api.di.Provides;
29  import org.apache.maven.api.plugin.testing.InjectMojo;
30  import org.apache.maven.api.plugin.testing.MojoParameter;
31  import org.apache.maven.api.plugin.testing.MojoTest;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.model.Dependency;
34  import org.apache.maven.model.DependencyManagement;
35  import org.apache.maven.model.Exclusion;
36  import org.apache.maven.model.InputLocation;
37  import org.apache.maven.model.InputSource;
38  import org.apache.maven.plugin.MojoExecutionException;
39  import org.apache.maven.plugin.logging.Log;
40  import org.apache.maven.plugins.dependency.utils.ResolverUtil;
41  import org.apache.maven.project.MavenProject;
42  import org.eclipse.aether.DefaultRepositorySystemSession;
43  import org.eclipse.aether.artifact.DefaultArtifact;
44  import org.junit.jupiter.api.BeforeEach;
45  import org.junit.jupiter.api.Test;
46  import org.junit.jupiter.api.extension.ExtendWith;
47  import org.mockito.Mock;
48  import org.mockito.junit.jupiter.MockitoExtension;
49  
50  import static org.assertj.core.api.Assertions.assertThatCode;
51  import static org.assertj.core.api.Assertions.assertThatThrownBy;
52  import static org.mockito.ArgumentMatchers.any;
53  import static org.mockito.ArgumentMatchers.anyString;
54  import static org.mockito.Mockito.lenient;
55  import static org.mockito.Mockito.mock;
56  import static org.mockito.Mockito.never;
57  import static org.mockito.Mockito.times;
58  import static org.mockito.Mockito.verify;
59  import static org.mockito.Mockito.when;
60  
61  @ExtendWith(MockitoExtension.class)
62  @MojoTest
63  class AnalyzeExclusionsMojoTest {
64  
65      @Inject
66      private MavenProject project;
67  
68      @Inject
69      private MavenSession mavenSession;
70  
71      @Inject
72      private Log testLog;
73  
74      @Mock
75      private ResolverUtil resolverUtil;
76  
77      @Provides
78      private ResolverUtil resolverUtilProvides() {
79          return resolverUtil;
80      }
81  
82      @BeforeEach
83      void setUp() {
84          when(project.getGroupId()).thenReturn("testGroupId");
85          when(project.getArtifactId()).thenReturn("testArtifactId");
86          when(project.getVersion()).thenReturn("1.0.0");
87  
88          DependencyManagement dependencyManagement = mock(DependencyManagement.class);
89          when(dependencyManagement.getDependencies()).thenReturn(Collections.emptyList());
90          when(project.getDependencyManagement()).thenReturn(dependencyManagement);
91  
92          lenient().when(mavenSession.getRepositorySession()).thenReturn(new DefaultRepositorySystemSession());
93      }
94  
95      @Test
96      @InjectMojo(goal = "analyze-exclusions")
97      @MojoParameter(name = "exclusionFail", value = "true")
98      void testShallThrowExceptionWhenFailOnWarning(AnalyzeExclusionsMojo mojo) {
99          List<Dependency> dependencies = new ArrayList<>();
100         Dependency withInvalidExclusion = dependency("a", "b");
101         withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
102         dependencies.add(withInvalidExclusion);
103         when(project.getDependencies()).thenReturn(dependencies);
104 
105         assertThatThrownBy(mojo::execute)
106                 .isInstanceOf(MojoExecutionException.class)
107                 .hasMessageContaining("Invalid exclusions found");
108 
109         verify(testLog, times(3)).error(anyString());
110     }
111 
112     @Test
113     @InjectMojo(goal = "analyze-exclusions")
114     @MojoParameter(name = "exclusionFail", value = "false")
115     void testShallLogWarningWhenFailOnWarningIsFalse(AnalyzeExclusionsMojo mojo) throws Exception {
116         List<Dependency> dependencies = new ArrayList<>();
117         Dependency withInvalidExclusion = dependency("a", "b");
118         withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
119         dependencies.add(withInvalidExclusion);
120         when(project.getDependencies()).thenReturn(dependencies);
121 
122         mojo.execute();
123 
124         verify(testLog, times(3)).warn(anyString());
125     }
126 
127     @Test
128     @InjectMojo(goal = "analyze-exclusions")
129     void testShallExitWithoutAnalyzeWhenNoDependencyHasExclusion(AnalyzeExclusionsMojo mojo) throws Exception {
130         List<Dependency> dependencies = new ArrayList<>();
131         dependencies.add(dependency("a", "c"));
132         when(project.getDependencies()).thenReturn(dependencies);
133 
134         mojo.execute();
135         verify(testLog).debug("No dependencies defined with exclusions - exiting");
136     }
137 
138     @Test
139     @InjectMojo(goal = "analyze-exclusions")
140     void testShallNotReportInvalidExclusionForWildcardGroupIdAndArtifactId(AnalyzeExclusionsMojo mojo)
141             throws Exception {
142         Dependency dependencyWithWildcardExclusion = dependency("a", "b");
143         dependencyWithWildcardExclusion.addExclusion(exclusion("*", "*"));
144         when(project.getDependencies()).thenReturn(Collections.singletonList(dependencyWithWildcardExclusion));
145 
146         when(resolverUtil.collectDependencies(any()))
147                 .thenReturn(Collections.singletonList(new org.eclipse.aether.graph.Dependency(
148                         new DefaultArtifact("whatever", "ok", "jar", "1.0"), "")));
149 
150         mojo.execute();
151         verify(testLog, never()).warn(anyString());
152     }
153 
154     @Test
155     @InjectMojo(goal = "analyze-exclusions")
156     void testCanResolveMultipleArtifactsWithEqualGroupIdAndArtifactId(AnalyzeExclusionsMojo mojo) {
157         Dependency dependency1 = dependency("a", "b");
158         Dependency dependency2 = dependency("a", "b", "compile", "native");
159         dependency1.addExclusion(exclusion("c", "d"));
160         dependency2.addExclusion(exclusion("c", "d"));
161         when(project.getDependencies()).thenReturn(Arrays.asList(dependency1, dependency2));
162 
163         assertThatCode(mojo::execute).doesNotThrowAnyException();
164     }
165 
166     @Test
167     @InjectMojo(goal = "analyze-exclusions")
168     void testShallNotLogWhenExclusionIsValid(AnalyzeExclusionsMojo mojo) throws Exception {
169         List<Dependency> dependencies = new ArrayList<>();
170         Dependency dependency = dependency("a", "b");
171         dependency.addExclusion(exclusion("ok", "ok"));
172         dependencies.add(dependency);
173         when(project.getDependencies()).thenReturn(dependencies);
174 
175         when(resolverUtil.collectDependencies(any()))
176                 .thenReturn(Collections.singletonList(
177                         new org.eclipse.aether.graph.Dependency(new DefaultArtifact("ok", "ok", "jar", "1.0"), "")));
178 
179         assertThatCode(mojo::execute).doesNotThrowAnyException();
180 
181         verify(testLog, never()).warn(anyString());
182     }
183 
184     @Test
185     @InjectMojo(goal = "analyze-exclusions")
186     void testThatLogContainProjectName(AnalyzeExclusionsMojo mojo) throws Exception {
187         List<Dependency> dependencies = new ArrayList<>();
188         Dependency withInvalidExclusion = dependency("a", "b");
189         withInvalidExclusion.addExclusion(exclusion("invalid", "invalid"));
190         dependencies.add(withInvalidExclusion);
191         when(project.getDependencies()).thenReturn(dependencies);
192 
193         when(project.getName()).thenReturn("projectName");
194 
195         mojo.execute();
196 
197         verify(testLog).warn("projectName defines following unnecessary excludes");
198     }
199 
200     private Dependency dependency(String groupId, String artifactId) {
201         Dependency dependency = new Dependency();
202         dependency.setGroupId(groupId);
203         dependency.setArtifactId(artifactId);
204         dependency.setVersion("1.0");
205         dependency.setScope("compile");
206         dependency.setType("jar");
207         dependency.setClassifier("");
208         dependency.setLocation("", new InputLocation(1, 1));
209         return dependency;
210     }
211 
212     private Dependency dependency(String groupId, String artifactId, String scope, String classifier) {
213         Dependency dependency = new Dependency();
214         dependency.setGroupId(groupId);
215         dependency.setArtifactId(artifactId);
216         dependency.setVersion("1.0");
217         dependency.setScope(scope);
218         dependency.setType("jar");
219         dependency.setClassifier(classifier);
220         dependency.setLocation("", new InputLocation(1, 1));
221         return dependency;
222     }
223 
224     private Exclusion exclusion(String groupId, String artifactId) {
225         Exclusion exclusion = new Exclusion();
226         exclusion.setGroupId(groupId);
227         exclusion.setArtifactId(artifactId);
228         InputSource inputSource = new InputSource();
229         inputSource.setModelId("testGroupId:testArtifactId:1.0.0");
230         exclusion.setLocation("", new InputLocation(1, 1, inputSource));
231         return exclusion;
232     }
233 }