001package org.apache.maven.plugins.enforcer;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import static org.junit.jupiter.api.Assertions.*;
023
024import org.apache.maven.enforcer.rule.api.EnforcerRule;
025import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
026import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
027import org.apache.maven.plugin.MojoExecutionException;
028import org.apache.maven.plugin.logging.Log;
029import org.junit.jupiter.api.Test;
030import org.junit.jupiter.api.extension.ExtendWith;
031import org.mockito.InjectMocks;
032import org.mockito.Mockito;
033import org.mockito.junit.jupiter.MockitoExtension;
034import org.mockito.junit.jupiter.MockitoSettings;
035import org.mockito.quality.Strictness;
036
037/**
038 * Exhaustively check the enforcer mojo.
039 * 
040 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
041 */
042@ExtendWith( MockitoExtension.class )
043@MockitoSettings( strictness = Strictness.LENIENT )
044public class TestEnforceMojo
045{
046
047    @InjectMocks
048    EnforceMojo mojo;
049
050    @Test
051    public void testEnforceMojo()
052        throws MojoExecutionException
053    {
054        setupBasics( false );
055
056        try
057        {
058            mojo.execute();
059            fail( "Expected a Mojo Execution Exception." );
060        }
061        catch ( MojoExecutionException e )
062        {
063            System.out.println( "Caught Expected Exception:" + e.getLocalizedMessage() );
064        }
065
066        EnforcerRule[] rules = new EnforcerRule[10];
067        rules[0] = new MockEnforcerRule( true );
068        rules[1] = new MockEnforcerRule( true );
069        mojo.setRules( rules );
070
071        mojo.execute();
072
073        try
074        {
075            mojo.setFailFast( false );
076            mojo.setFail( true );
077            mojo.execute();
078            fail( "Expected a Mojo Execution Exception." );
079        }
080        catch ( MojoExecutionException e )
081        {
082            System.out.println( "Caught Expected Exception:" + e.getLocalizedMessage() );
083        }
084
085        try
086        {
087            mojo.setFailFast( true );
088            mojo.setFail( true );
089            mojo.execute();
090            fail( "Expected a Mojo Execution Exception." );
091        }
092        catch ( MojoExecutionException e )
093        {
094            System.out.println( "Caught Expected Exception:" + e.getLocalizedMessage() );
095        }
096
097        ( (MockEnforcerRule) rules[0] ).setFailRule( false );
098        ( (MockEnforcerRule) rules[1] ).setFailRule( false );
099        mojo.execute();
100
101    }
102
103    @Test
104    public void testCaching()
105        throws MojoExecutionException
106    {
107        setupBasics( true );
108
109        MockEnforcerRule[] rules = new MockEnforcerRule[10];
110
111        // check that basic caching works.
112        rules[0] = new MockEnforcerRule( false, "", true, true );
113        rules[1] = new MockEnforcerRule( false, "", true, true );
114        mojo.setRules( rules );
115
116        EnforceMojo.cache.clear();
117        mojo.execute();
118
119        assertTrue( rules[0].executed, "Expected this rule to be executed." );
120        assertFalse( rules[1].executed, "Expected this rule not to be executed." );
121
122        // check that skip caching works.
123        rules[0] = new MockEnforcerRule( false, "", true, true );
124        rules[1] = new MockEnforcerRule( false, "", true, true );
125        mojo.setRules( rules );
126
127        EnforceMojo.cache.clear();
128        mojo.ignoreCache = true;
129        mojo.execute();
130
131        assertTrue( rules[0].executed, "Expected this rule to be executed." );
132        assertTrue( rules[1].executed, "Expected this rule to be executed." );
133
134        mojo.ignoreCache = false;
135
136        // check that different ids are compared.
137        rules[0] = new MockEnforcerRule( false, "1", true, true );
138        rules[1] = new MockEnforcerRule( false, "2", true, true );
139        rules[2] = new MockEnforcerRule( false, "2", true, true );
140        mojo.setRules( rules );
141
142        EnforceMojo.cache.clear();
143        mojo.execute();
144
145        assertTrue( rules[0].executed, "Expected this rule to be executed." );
146        assertTrue( rules[1].executed, "Expected this rule to be executed." );
147        assertFalse( rules[2].executed, "Expected this rule not to be executed." );
148
149        // check that future overrides are working
150        rules[0] = new MockEnforcerRule( false, "1", true, true );
151        rules[1] = new MockEnforcerRule( false, "1", false, true );
152        rules[2] = null;
153        mojo.setRules( rules );
154
155        EnforceMojo.cache.clear();
156        mojo.execute();
157
158        assertTrue( rules[0].executed, "Expected this rule to be executed." );
159        assertTrue( rules[1].executed, "Expected this rule to be executed." );
160
161        // check that future isResultValid is used
162        rules[0] = new MockEnforcerRule( false, "1", true, true );
163        rules[1] = new MockEnforcerRule( false, "1", true, false );
164        rules[2] = null;
165        mojo.setRules( rules );
166
167        EnforceMojo.cache.clear();
168        mojo.execute();
169
170        assertTrue( rules[0].executed, "Expected this rule to be executed." );
171        assertTrue( rules[1].executed, "Expected this rule to be executed." );
172
173    }
174
175    @Test
176    public void testCachePersistence1()
177        throws MojoExecutionException
178    {
179        setupBasics( true );
180
181        MockEnforcerRule[] rules = new MockEnforcerRule[10];
182
183        // check that basic caching works.
184        rules[0] = new MockEnforcerRule( false, "", true, true );
185        rules[1] = new MockEnforcerRule( false, "", true, true );
186        mojo.setRules( rules );
187
188        EnforceMojo.cache.clear();
189        mojo.execute();
190
191        assertTrue( rules[0].executed, "Expected this rule to be executed." );
192        assertFalse( rules[1].executed, "Expected this rule not to be executed." );
193
194    }
195
196    @Test
197    public void testCachePersistence2()
198        throws MojoExecutionException
199    {
200        setupBasics( true );
201
202        MockEnforcerRule[] rules = new MockEnforcerRule[10];
203
204        // check that basic caching works.
205        rules[0] = new MockEnforcerRule( false, "", true, true );
206        rules[1] = new MockEnforcerRule( false, "", true, true );
207        mojo.setRules( rules );
208
209        mojo.execute();
210
211        assertFalse( rules[0].executed, "Expected this rule not to be executed." );
212        assertFalse( rules[1].executed, "Expected this rule not to be executed." );
213
214    }
215
216    @Test
217    public void testCachePersistence3()
218        throws MojoExecutionException
219    {
220        System.gc();
221
222        try
223        {
224            Thread.sleep( 1000 );
225        }
226        catch ( InterruptedException e )
227        {
228        }
229
230        setupBasics( true );
231
232        MockEnforcerRule[] rules = new MockEnforcerRule[10];
233
234        // check that basic caching works.
235        rules[0] = new MockEnforcerRule( false, "", true, true );
236        rules[1] = new MockEnforcerRule( false, "", true, true );
237        mojo.setRules( rules );
238
239        mojo.execute();
240
241        assertFalse( rules[0].executed, "Expected this rule not to be executed." );
242        assertFalse( rules[1].executed, "Expected this rule not to be executed." );
243
244    }
245
246    @Test
247    public void testLoggingOnEnforcerRuleExceptionWithMessage()
248        throws MojoExecutionException, EnforcerRuleException
249    {
250        // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
251        setupBasics( false );
252
253        // the regular kind of EnforcerRuleException:
254        EnforcerRuleException ruleException = new EnforcerRuleException( "testMessage" );
255
256        EnforcerRule ruleMock = Mockito.mock( EnforcerRule.class );
257        Mockito.doThrow( ruleException ).when( ruleMock ).execute( Mockito.any( EnforcerRuleHelper.class ) );
258
259        mojo.setRules( new EnforcerRule[] { ruleMock } );
260
261        Log logSpy = setupLogSpy();
262
263        mojo.execute();
264
265        Mockito.verify( logSpy ).debug( Mockito.anyString(), Mockito.same( ruleException ) );
266
267        Mockito.verify( logSpy, Mockito.never() ).warn( Mockito.anyString(), Mockito.any( Throwable.class ) );
268
269        Mockito.verify( logSpy ).warn( Mockito.matches( ".* failed with message:" + System.lineSeparator()
270            + ruleException.getMessage() ) );
271    }
272
273    @Test
274    public void testLoggingOnEnforcerRuleExceptionWithoutMessage()
275        throws MojoExecutionException, EnforcerRuleException
276    {
277        // fail=false because this is out of scope here (also allows for cleaner test code without catch block)
278        setupBasics( false );
279
280        // emulate behaviour of various rules that just catch Exception and wrap into EnforcerRuleException:
281        NullPointerException npe = new NullPointerException();
282        EnforcerRuleException enforcerRuleException = new EnforcerRuleException( npe.getLocalizedMessage(), npe );
283
284        EnforcerRule ruleMock = Mockito.mock( EnforcerRule.class );
285        Mockito.doThrow( enforcerRuleException ).when( ruleMock ).execute( Mockito.any( EnforcerRuleHelper.class ) );
286
287        mojo.setRules( new EnforcerRule[] { ruleMock } );
288
289        Log logSpy = setupLogSpy();
290
291        mojo.execute();
292
293        Mockito.verify( logSpy ).warn( Mockito.contains( "failed without a message" ),
294                                       Mockito.same( enforcerRuleException ) );
295
296        Mockito.verify( logSpy ).warn( Mockito.matches( ".* failed with message:" + System.lineSeparator() + "null" ) );
297    }
298
299    private void setupBasics( boolean fail )
300    {
301        mojo.setFail( fail );
302        mojo.setSession( EnforcerTestUtils.getMavenSession() );
303        mojo.setProject( new MockProject() );
304    }
305
306    private Log setupLogSpy()
307    {
308        Log spy = Mockito.spy( mojo.getLog() );
309        mojo.setLog( spy );
310        return spy;
311    }
312}