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.enforcer;
20  
21  import java.util.Arrays;
22  import java.util.Collections;
23  import java.util.List;
24  
25  import org.apache.maven.enforcer.rule.api.EnforcerLevel;
26  import org.apache.maven.enforcer.rule.api.EnforcerRule;
27  import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
28  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
29  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
30  import org.apache.maven.execution.MavenSession;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.logging.Log;
33  import org.apache.maven.plugins.enforcer.internal.EnforcerRuleDesc;
34  import org.apache.maven.plugins.enforcer.internal.EnforcerRuleManager;
35  import org.assertj.core.api.Assertions;
36  import org.junit.jupiter.api.Test;
37  import org.junit.jupiter.api.extension.ExtendWith;
38  import org.mockito.InjectMocks;
39  import org.mockito.Mock;
40  import org.mockito.Mockito;
41  import org.mockito.junit.jupiter.MockitoExtension;
42  import org.mockito.junit.jupiter.MockitoSettings;
43  import org.mockito.quality.Strictness;
44  
45  import static org.assertj.core.api.Assertions.assertThatCode;
46  import static org.assertj.core.api.Assertions.assertThatThrownBy;
47  import static org.junit.jupiter.api.Assertions.assertFalse;
48  import static org.junit.jupiter.api.Assertions.assertTrue;
49  import static org.junit.jupiter.api.Assertions.fail;
50  import static org.mockito.ArgumentMatchers.any;
51  import static org.mockito.Mockito.verify;
52  import static org.mockito.Mockito.when;
53  
54  /**
55   * Exhaustively check the enforcer mojo.
56   *
57   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
58   */
59  @ExtendWith(MockitoExtension.class)
60  @MockitoSettings(strictness = Strictness.LENIENT)
61  class TestEnforceMojo {
62  
63      @Mock
64      private EnforcerRuleManager ruleManager;
65  
66      @Mock
67      private MavenSession session;
68  
69      @InjectMocks
70      private EnforceMojo mojo;
71  
72      @Test
73      void emptyRuleListShouldThrowException() {
74          mojo.setFail(false);
75  
76          assertThatCode(() -> mojo.execute())
77                  .isInstanceOf(MojoExecutionException.class)
78                  .hasMessage("No rules are configured. Use the skip flag if you want to disable execution.");
79      }
80  
81      @Test
82      void failedRulesAndNoFailPassBuild() throws Exception {
83          // set fail to false
84          mojo.setFail(false);
85  
86          Log logSpy = setupLogSpy();
87  
88          // two rules which fail
89          EnforcerRuleDesc[] rules = new EnforcerRuleDesc[2];
90          rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
91          rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
92  
93          when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
94  
95          mojo.execute();
96  
97          verify(logSpy)
98                  .warn(Mockito.contains(
99                          "Rule 0: org.apache.maven.plugins.enforcer.MockEnforcerRule failed with message"));
100         verify(logSpy)
101                 .warn(Mockito.contains(
102                         "Rule 1: org.apache.maven.plugins.enforcer.MockEnforcerRule failed with message"));
103     }
104 
105     @Test
106     void breakBuildImmediately() throws Exception {
107         // set fail to false
108         mojo.setFail(false);
109 
110         Log logSpy = setupLogSpy();
111 
112         // this rule break build immediately
113         EnforcerRule ruleBreakBuild = Mockito.mock(EnforcerRule.class);
114         Mockito.doThrow(EnforcerRuleError.class).when(ruleBreakBuild).execute(any(EnforcerRuleHelper.class));
115 
116         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[3];
117         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false));
118         rules[1] = new EnforcerRuleDesc("ruleBreakBuild", ruleBreakBuild);
119         rules[2] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false));
120 
121         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
122 
123         Assertions.assertThatCode(() -> mojo.execute())
124                 .isInstanceOf(MojoExecutionException.class)
125                 .hasCauseInstanceOf(EnforcerRuleError.class);
126 
127         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
128         assertFalse(((MockEnforcerRule) rules[2].getRule()).executed, "Expected this rule to be not executed.");
129 
130         verify(logSpy).info(Mockito.contains("Rule 0: org.apache.maven.plugins.enforcer.MockEnforcerRule passed"));
131     }
132 
133     @Test
134     void testEnforceMojo() throws Exception {
135         mojo.setFail(true);
136 
137         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[2];
138         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
139         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(true));
140 
141         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
142 
143         try {
144             mojo.setFailFast(false);
145             mojo.setFail(true);
146             mojo.execute();
147             fail("Expected a Mojo Execution Exception.");
148         } catch (MojoExecutionException e) {
149             System.out.println("Caught Expected Exception:" + e.getLocalizedMessage());
150         }
151 
152         try {
153             mojo.setFailFast(true);
154             mojo.setFail(true);
155             mojo.execute();
156             fail("Expected a Mojo Execution Exception.");
157         } catch (MojoExecutionException e) {
158             System.out.println("Caught Expected Exception:" + e.getLocalizedMessage());
159         }
160 
161         ((MockEnforcerRule) rules[0].getRule()).setFailRule(false);
162         ((MockEnforcerRule) rules[1].getRule()).setFailRule(false);
163         mojo.execute();
164     }
165 
166     @Test
167     void testCaching() throws Exception {
168         mojo.setFail(true);
169 
170         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
171 
172         // check that basic caching works.
173         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
174         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
175         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
176 
177         EnforceMojo.cache.clear();
178         mojo.execute();
179 
180         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
181         assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
182 
183         // check that skip caching works.
184         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
185         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
186         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
187 
188         EnforceMojo.cache.clear();
189         mojo.ignoreCache = true;
190         mojo.execute();
191 
192         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
193         assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
194 
195         mojo.ignoreCache = false;
196 
197         // check that different ids are compared.
198         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
199         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "2", true, true));
200         rules[2] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "2", true, true));
201         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
202 
203         EnforceMojo.cache.clear();
204         mojo.execute();
205 
206         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
207         assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
208         assertFalse(((MockEnforcerRule) rules[2].getRule()).executed, "Expected this rule not to be executed.");
209 
210         // check that future overrides are working
211         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
212         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", false, true));
213         rules[2] = null;
214         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
215 
216         EnforceMojo.cache.clear();
217         mojo.execute();
218 
219         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
220         assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
221 
222         // check that future isResultValid is used
223         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, true));
224         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "1", true, false));
225         rules[2] = null;
226         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
227 
228         EnforceMojo.cache.clear();
229         mojo.execute();
230 
231         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
232         assertTrue(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule to be executed.");
233     }
234 
235     @Test
236     void testCachePersistence1() throws Exception {
237         mojo.setFail(true);
238 
239         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
240 
241         // check that basic caching works.
242         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
243         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
244         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
245 
246         EnforceMojo.cache.clear();
247         mojo.execute();
248 
249         assertTrue(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule to be executed.");
250         assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
251     }
252 
253     @Test
254     void testCachePersistence2() throws Exception {
255         mojo.setFail(true);
256 
257         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
258 
259         // check that basic caching works.
260         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
261         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
262         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
263 
264         mojo.execute();
265 
266         assertFalse(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule not to be executed.");
267         assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
268     }
269 
270     @Test
271     void testCachePersistence3() throws Exception {
272         System.gc();
273 
274         try {
275             Thread.sleep(1000);
276         } catch (InterruptedException e) {
277         }
278 
279         mojo.setFail(true);
280 
281         EnforcerRuleDesc[] rules = new EnforcerRuleDesc[10];
282 
283         // check that basic caching works.
284         rules[0] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
285         rules[1] = new EnforcerRuleDesc("mockEnforcerRule", new MockEnforcerRule(false, "", true, true));
286         when(ruleManager.createRules(any(), any())).thenReturn(Arrays.asList(rules));
287 
288         mojo.execute();
289 
290         assertFalse(((MockEnforcerRule) rules[0].getRule()).executed, "Expected this rule not to be executed.");
291         assertFalse(((MockEnforcerRule) rules[1].getRule()).executed, "Expected this rule not to be executed.");
292     }
293 
294     @Test
295     void testLoggingOnEnforcerRuleExceptionWithMessage() throws Exception {
296         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
297         mojo.setFail(false);
298 
299         // the regular kind of EnforcerRuleException:
300         EnforcerRuleException ruleException = new EnforcerRuleException("testMessage");
301 
302         EnforcerRule ruleMock = Mockito.mock(EnforcerRule.class);
303         when(ruleMock.getLevel()).thenReturn(EnforcerLevel.ERROR);
304         Mockito.doThrow(ruleException).when(ruleMock).execute(any(EnforcerRuleHelper.class));
305         when(ruleManager.createRules(any(), any()))
306                 .thenReturn(Collections.singletonList(new EnforcerRuleDesc("mock", ruleMock)));
307 
308         Log logSpy = setupLogSpy();
309 
310         mojo.execute();
311 
312         verify(logSpy, Mockito.never()).warn(Mockito.anyString(), any(Throwable.class));
313 
314         verify(logSpy)
315                 .warn(Mockito.matches(".* failed with message:" + System.lineSeparator() + ruleException.getMessage()));
316     }
317 
318     @Test
319     void testLoggingOnEnforcerRuleExceptionWithoutMessage() throws Exception {
320         // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
321         mojo.setFail(false);
322 
323         // emulate behaviour of various rules that just catch Exception and wrap into EnforcerRuleException:
324         NullPointerException npe = new NullPointerException();
325         EnforcerRuleException enforcerRuleException = new EnforcerRuleException(npe.getLocalizedMessage(), npe);
326 
327         EnforcerRule ruleMock = Mockito.mock(EnforcerRule.class);
328         when(ruleMock.getLevel()).thenReturn(EnforcerLevel.ERROR);
329         Mockito.doThrow(enforcerRuleException).when(ruleMock).execute(any(EnforcerRuleHelper.class));
330 
331         when(ruleManager.createRules(any(), any()))
332                 .thenReturn(Collections.singletonList(new EnforcerRuleDesc("mock", ruleMock)));
333 
334         Log logSpy = setupLogSpy();
335 
336         mojo.execute();
337 
338         Mockito.verify(logSpy).warn(Mockito.matches(".* failed without a message"));
339     }
340 
341     @Test
342     void testFailIfNoTests() throws MojoExecutionException {
343         mojo.setFail(false);
344         mojo.setFailIfNoRules(false);
345 
346         Log logSpy = setupLogSpy();
347 
348         mojo.execute();
349 
350         verify(logSpy).warn("No rules are configured.");
351         Mockito.verifyNoMoreInteractions(logSpy);
352     }
353 
354     @Test
355     void testFailIfBothRuleOverridePropertiesAreSet() throws MojoExecutionException {
356         mojo.setFail(false);
357 
358         Log logSpy = setupLogSpy();
359         List<String> rules = Arrays.asList("rule1", "rule2");
360         mojo.setRulesToExecute(rules);
361 
362         assertThatThrownBy(() -> mojo.setCommandLineRules(rules))
363                 .isInstanceOf(MojoExecutionException.class)
364                 .hasMessageContaining(
365                         "Detected the usage of both '-Drules' (which is deprecated) and '-Denforcer.rules'");
366     }
367 
368     @Test
369     void testShouldPrintWarnWhenUsingDeprecatedRulesProperty() throws MojoExecutionException {
370         mojo.setFail(false);
371 
372         Log logSpy = setupLogSpy();
373 
374         mojo.setCommandLineRules(Arrays.asList("rule1", "rule2"));
375 
376         Mockito.verify(logSpy)
377                 .warn("Detected the usage of property '-Drules' which is deprecated. Use '-Denforcer.rules' instead.");
378     }
379 
380     @Test
381     void testShouldNotPrintWarnWhenDeprecatedRulesPropertyIsEmpty() throws MojoExecutionException {
382         mojo.setFail(false);
383 
384         Log logSpy = setupLogSpy();
385 
386         mojo.setCommandLineRules(Collections.emptyList());
387 
388         Mockito.verifyNoInteractions(logSpy);
389     }
390 
391     private Log setupLogSpy() {
392         Log spy = Mockito.spy(mojo.getLog());
393         mojo.setLog(spy);
394         return spy;
395     }
396 }