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