View Javadoc
1   /*
2    * Copyright (c) 2002-2025, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.web.system;
35  
36  import java.io.File;
37  import java.io.FileInputStream;
38  import java.io.FileOutputStream;
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.io.OutputStream;
42  import java.math.BigInteger;
43  import java.security.SecureRandom;
44  import java.util.Locale;
45  import java.util.Properties;
46  import java.util.Random;
47  
48  import org.springframework.mock.web.MockHttpServletRequest;
49  
50  import fr.paris.lutece.portal.business.user.AdminUser;
51  import fr.paris.lutece.portal.service.admin.AccessDeniedException;
52  import fr.paris.lutece.portal.service.cache.AbstractCacheableService;
53  import fr.paris.lutece.portal.service.cache.CacheService;
54  import fr.paris.lutece.portal.service.cache.CacheableService;
55  import fr.paris.lutece.portal.service.i18n.I18nService;
56  import fr.paris.lutece.portal.service.message.AdminMessage;
57  import fr.paris.lutece.portal.service.message.AdminMessageService;
58  import fr.paris.lutece.portal.service.security.SecurityTokenService;
59  import fr.paris.lutece.portal.service.util.AppPropertiesService;
60  import fr.paris.lutece.test.LuteceTestCase;
61  import fr.paris.lutece.test.Utils;
62  import net.sf.ehcache.Ehcache;
63  import net.sf.ehcache.event.CacheEventListenerAdapter;
64  
65  /**
66   * SystemJspBean Test Class
67   *
68   */
69  public class CacheJspBeanTest extends LuteceTestCase
70  {
71  
72      /**
73       * Test of getManageCaches method, of class fr.paris.lutece.portal.web.system.SystemJspBean.
74       */
75      public void testGetManageCaches( ) throws AccessDeniedException
76      {
77          MockHttpServletRequest request = new MockHttpServletRequest( );
78          Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
79  
80          CacheJspBean instance = new CacheJspBean( );
81          instance.init( request, CacheJspBean.RIGHT_CACHE_MANAGEMENT );
82          assertNotNull( instance.getManageCaches( request ) );
83      }
84  
85      /**
86       * Test of doResetCaches method, of class fr.paris.lutece.portal.web.system.SystemJspBean.
87       * 
88       * @throws AccessDeniedException
89       */
90      public void testDoResetCaches( ) throws AccessDeniedException
91      {
92          CacheListener cacheEventListener = new CacheListener( );
93          long registeredListener = CacheService.getCacheableServicesList( ).stream( )
94                  .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
95                  .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
96                  .peek( rel -> rel.registerListener( cacheEventListener ) ).count( );
97          assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
98          MockHttpServletRequest request = new MockHttpServletRequest( );
99          Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
100         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
101                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) );
102         CacheJspBean.doResetCaches( request );
103         assertEquals( "Not all AbstractCacheableService were reset", registeredListener, cacheEventListener.getCallCount( ) );
104     }
105 
106     public void testDoResetCachesInvalidToken( ) throws AccessDeniedException
107     {
108         CacheListener cacheEventListener = new CacheListener( );
109         long registeredListener = CacheService.getCacheableServicesList( ).stream( )
110                 .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
111                 .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
112                 .peek( rel -> rel.registerListener( cacheEventListener ) ).count( );
113         assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
114         MockHttpServletRequest request = new MockHttpServletRequest( );
115         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
116         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
117                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) + "b" );
118         try
119         {
120             CacheJspBean.doResetCaches( request );
121             fail( "Should have thrown" );
122         }
123         catch( AccessDeniedException e )
124         {
125             assertEquals( "No cache should have been reset", 0, cacheEventListener.getCallCount( ) );
126         }
127     }
128 
129     public void testDoResetCachesNoToken( ) throws AccessDeniedException
130     {
131         CacheListener cacheEventListener = new CacheListener( );
132         long registeredListener = CacheService.getCacheableServicesList( ).stream( )
133                 .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
134                 .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
135                 .peek( rel -> rel.registerListener( cacheEventListener ) ).count( );
136         assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
137         MockHttpServletRequest request = new MockHttpServletRequest( );
138         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
139         try
140         {
141             CacheJspBean.doResetCaches( request );
142             fail( "Should have thrown" );
143         }
144         catch( AccessDeniedException e )
145         {
146             assertEquals( "No cache should have been reset", 0, cacheEventListener.getCallCount( ) );
147         }
148     }
149 
150     public void testDoResetCachesOneCache( ) throws AccessDeniedException
151     {
152         CacheListener cacheEventListener = new CacheListener( );
153         int cacheIndex = -1;
154         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
155         {
156             cacheIndex++;
157             if ( service instanceof AbstractCacheableService )
158             {
159                 ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ).registerListener( cacheEventListener );
160                 break;
161             }
162         }
163         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
164         CacheListener allCacheEventListener = new CacheListener( );
165         long registeredListener = CacheService.getCacheableServicesList( ).stream( )
166                 .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
167                 .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
168                 .peek( rel -> rel.registerListener( allCacheEventListener ) ).count( );
169         assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
170         MockHttpServletRequest request = new MockHttpServletRequest( );
171         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
172         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
173         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
174                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) );
175         CacheJspBean.doResetCaches( request );
176         assertEquals( "Only one cache should have been reset", 1, allCacheEventListener.getCallCount( ) );
177         assertEquals( "The target cache should have been reset", 1, cacheEventListener.getCallCount( ) );
178     }
179 
180     public void testDoResetCachesOneCacheInvalidToken( ) throws AccessDeniedException
181     {
182         CacheListener cacheEventListener = new CacheListener( );
183         int cacheIndex = -1;
184         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
185         {
186             cacheIndex++;
187             if ( service instanceof AbstractCacheableService )
188             {
189                 ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ).registerListener( cacheEventListener );
190                 break;
191             }
192         }
193         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
194         CacheListener allCacheEventListener = new CacheListener( );
195         long registeredListener = CacheService.getCacheableServicesList( ).stream( )
196                 .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
197                 .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
198                 .peek( rel -> rel.registerListener( allCacheEventListener ) ).count( );
199         assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
200         MockHttpServletRequest request = new MockHttpServletRequest( );
201         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
202         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
203         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
204                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) + "b" );
205         try
206         {
207             CacheJspBean.doResetCaches( request );
208             fail( "Should have thrown" );
209         }
210         catch( AccessDeniedException e )
211         {
212             assertEquals( "No cache should have been reset", 0, allCacheEventListener.getCallCount( ) );
213             assertEquals( "No cache should have been reset", 0, cacheEventListener.getCallCount( ) );
214         }
215     }
216 
217     public void testDoResetCachesOneCacheNoToken( ) throws AccessDeniedException
218     {
219         CacheListener cacheEventListener = new CacheListener( );
220         int cacheIndex = -1;
221         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
222         {
223             cacheIndex++;
224             if ( service instanceof AbstractCacheableService )
225             {
226                 ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ).registerListener( cacheEventListener );
227                 break;
228             }
229         }
230         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
231         CacheListener allCacheEventListener = new CacheListener( );
232         long registeredListener = CacheService.getCacheableServicesList( ).stream( )
233                 .filter( service -> service instanceof AbstractCacheableService && service.isCacheEnable( ) )
234                 .map( service -> ( (AbstractCacheableService) service ).getCache( ).getCacheEventNotificationService( ) )
235                 .peek( rel -> rel.registerListener( allCacheEventListener ) ).count( );
236         assertFalse( "There should be at least one active AbstractCacheableService", 0 == registeredListener );
237         MockHttpServletRequest request = new MockHttpServletRequest( );
238         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
239         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
240         try
241         {
242             CacheJspBean.doResetCaches( request );
243             fail( "Should have thrown" );
244         }
245         catch( AccessDeniedException e )
246         {
247             assertEquals( "No cache should have been reset", 0, allCacheEventListener.getCallCount( ) );
248             assertEquals( "No cache should have been reset", 0, cacheEventListener.getCallCount( ) );
249         }
250     }
251 
252     public void testDoToggleCache( ) throws AccessDeniedException
253     {
254         int cacheIndex = -1;
255         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
256         {
257             cacheIndex++;
258             if ( service instanceof AbstractCacheableService )
259             {
260                 break;
261             }
262         }
263         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
264         MockHttpServletRequest request = new MockHttpServletRequest( );
265         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
266         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
267                 SecurityTokenService.getInstance( ).getToken( request, "jsp/admin/system/DoToggleCache.jsp" ) );
268         try
269         {
270             assertTrue( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
271             CacheJspBean.doToggleCache( request );
272             assertFalse( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
273         }
274         finally
275         {
276             CacheService.getCacheableServicesList( ).get( cacheIndex ).enableCache( true );
277         }
278     }
279 
280     public void testDoToggleCacheInvalidToken( ) throws AccessDeniedException
281     {
282         int cacheIndex = -1;
283         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
284         {
285             cacheIndex++;
286             if ( service instanceof AbstractCacheableService )
287             {
288                 break;
289             }
290         }
291         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
292         MockHttpServletRequest request = new MockHttpServletRequest( );
293         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
294         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
295                 SecurityTokenService.getInstance( ).getToken( request, "jsp/admin/system/DoToggleCache.jsp" ) + "b" );
296         try
297         {
298             assertTrue( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
299             CacheJspBean.doToggleCache( request );
300             fail( "Should have thrown" );
301         }
302         catch( AccessDeniedException e )
303         {
304             assertTrue( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
305         }
306         finally
307         {
308             CacheService.getCacheableServicesList( ).get( cacheIndex ).enableCache( true );
309         }
310     }
311 
312     public void testDoToggleCacheNoToken( ) throws AccessDeniedException
313     {
314         int cacheIndex = -1;
315         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
316         {
317             cacheIndex++;
318             if ( service instanceof AbstractCacheableService )
319             {
320                 break;
321             }
322         }
323         assertFalse( "There should be at least one active AbstractCacheableService", cacheIndex == -1 );
324         MockHttpServletRequest request = new MockHttpServletRequest( );
325         request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
326         try
327         {
328             assertTrue( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
329             CacheJspBean.doToggleCache( request );
330             fail( "Should have thrown" );
331         }
332         catch( AccessDeniedException e )
333         {
334             assertTrue( CacheService.getCacheableServicesList( ).get( cacheIndex ).isCacheEnable( ) );
335         }
336         finally
337         {
338             CacheService.getCacheableServicesList( ).get( cacheIndex ).enableCache( true );
339         }
340     }
341 
342     public void testGetConfirmToggleCache( )
343     {
344         CacheJspBean instance = new CacheJspBean( );
345         int cacheIndex = -1;
346         for ( CacheableService service : CacheService.getCacheableServicesList( ) )
347         {
348             cacheIndex++;
349             MockHttpServletRequest request = new MockHttpServletRequest( );
350             request.addParameter( "id_cache", Integer.toString( cacheIndex ) );
351             instance.getConfirmToggleCache( request );
352             AdminMessage message = AdminMessageService.getMessage( request );
353             assertNotNull( message );
354             assertEquals( AdminMessage.TYPE_CONFIRMATION, message.getType( ) );
355             for ( Locale locale : I18nService.getAdminAvailableLocales( ) )
356             {
357                 assertTrue( message.getText( locale ).contains( service.getName( ) ) );
358             }
359             assertTrue( message.getRequestParameters( ).containsKey( SecurityTokenService.PARAMETER_TOKEN ) );
360         }
361     }
362 
363     public void testGetConfirmToggleCacheNoParam( )
364     {
365         CacheJspBean instance = new CacheJspBean( );
366         MockHttpServletRequest request = new MockHttpServletRequest( );
367         instance.getConfirmToggleCache( request );
368         AdminMessage message = AdminMessageService.getMessage( request );
369         assertNotNull( message );
370         assertEquals( AdminMessage.TYPE_ERROR, message.getType( ) );
371     }
372 
373     /**
374      * Test of doReloadProperties method, of class fr.paris.lutece.portal.web.system.SystemJspBean.
375      * 
376      * @throws AccessDeniedException
377      * @throws IOException
378      */
379     public void testDoReloadProperties( ) throws AccessDeniedException, IOException
380     {
381         String property = "junit_testDoReloadProperties";
382         String propertyValue = getRandomName( );
383 
384         File luteceProperties = new File( getResourcesDir( ), "WEB-INF/conf/lutece.properties" );
385         Properties props = new Properties( );
386         InputStream is = new FileInputStream( luteceProperties );
387         props.load( is );
388         is.close( );
389         props.setProperty( property, propertyValue );
390 
391         OutputStream os = new FileOutputStream( luteceProperties );
392         props.store( os, "saved for junit " + this.getClass( ).getCanonicalName( ) );
393         os.close( );
394 
395         assertFalse( propertyValue.equals( AppPropertiesService.getProperty( property ) ) );
396 
397         MockHttpServletRequest request = new MockHttpServletRequest( );
398         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
399         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
400                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) );
401 
402         CacheJspBean instance = new CacheJspBean( );
403         instance.doReloadProperties( request );
404 
405         assertEquals( propertyValue, AppPropertiesService.getProperty( property ) );
406     }
407 
408     public void testDoReloadPropertiesInvalidToken( ) throws AccessDeniedException, IOException
409     {
410         String property = "junit_testDoReloadProperties";
411         String propertyValue = getRandomName( );
412 
413         File luteceProperties = new File( getResourcesDir( ), "WEB-INF/conf/lutece.properties" );
414         Properties props = new Properties( );
415         InputStream is = new FileInputStream( luteceProperties );
416         props.load( is );
417         is.close( );
418         props.setProperty( property, propertyValue );
419 
420         OutputStream os = new FileOutputStream( luteceProperties );
421         props.store( os, "saved for junit " + this.getClass( ).getCanonicalName( ) );
422         os.close( );
423 
424         assertFalse( propertyValue.equals( AppPropertiesService.getProperty( property ) ) );
425 
426         MockHttpServletRequest request = new MockHttpServletRequest( );
427         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
428         request.addParameter( SecurityTokenService.PARAMETER_TOKEN,
429                 SecurityTokenService.getInstance( ).getToken( request, "admin/system/manage_caches.html" ) + "b" );
430 
431         CacheJspBean instance = new CacheJspBean( );
432         try
433         {
434             instance.doReloadProperties( request );
435             fail( "Should have thrown" );
436         }
437         catch( AccessDeniedException e )
438         {
439             assertFalse( propertyValue.equals( AppPropertiesService.getProperty( property ) ) );
440         }
441     }
442 
443     public void testDoReloadPropertiesNoToken( ) throws AccessDeniedException, IOException
444     {
445         String property = "junit_testDoReloadProperties";
446         String propertyValue = getRandomName( );
447 
448         File luteceProperties = new File( getResourcesDir( ), "WEB-INF/conf/lutece.properties" );
449         Properties props = new Properties( );
450         InputStream is = new FileInputStream( luteceProperties );
451         props.load( is );
452         is.close( );
453         props.setProperty( property, propertyValue );
454 
455         OutputStream os = new FileOutputStream( luteceProperties );
456         props.store( os, "saved for junit " + this.getClass( ).getCanonicalName( ) );
457         os.close( );
458 
459         assertFalse( propertyValue.equals( AppPropertiesService.getProperty( property ) ) );
460 
461         MockHttpServletRequest request = new MockHttpServletRequest( );
462         Utils.registerAdminUserWithRigth( request, new AdminUser( ), CacheJspBean.RIGHT_CACHE_MANAGEMENT );
463 
464         CacheJspBean instance = new CacheJspBean( );
465         try
466         {
467             instance.doReloadProperties( request );
468             fail( "Should have thrown" );
469         }
470         catch( AccessDeniedException e )
471         {
472             assertFalse( propertyValue.equals( AppPropertiesService.getProperty( property ) ) );
473         }
474     }
475 
476     private String getRandomName( )
477     {
478         Random rand = new SecureRandom( );
479         BigInteger bigInt = new BigInteger( 128, rand );
480         return "junit" + bigInt.toString( 36 );
481     }
482 
483     private static final class CacheListener extends CacheEventListenerAdapter
484     {
485         private long _nCallCount = 0;
486 
487         @Override
488         public void notifyRemoveAll( Ehcache cache )
489         {
490             _nCallCount++;
491         }
492 
493         public long getCallCount( )
494         {
495             return _nCallCount;
496         }
497     }
498 }