View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration2.builder;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotSame;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.mockito.Mockito.mock;
25  import static org.mockito.Mockito.times;
26  import static org.mockito.Mockito.verify;
27  import static org.mockito.Mockito.verifyNoMoreInteractions;
28  import static org.mockito.Mockito.when;
29  
30  import java.util.HashMap;
31  import java.util.Map;
32  
33  import org.apache.commons.configuration2.PropertiesConfiguration;
34  import org.apache.commons.configuration2.ex.ConfigurationException;
35  import org.apache.commons.configuration2.io.FileHandler;
36  import org.apache.commons.configuration2.reloading.FileHandlerReloadingDetector;
37  import org.apache.commons.configuration2.reloading.ReloadingDetector;
38  import org.junit.jupiter.api.Test;
39  
40  /**
41   * Test class for {@code ReloadingFileBasedConfigurationBuilder}.
42   */
43  public class TestReloadingFileBasedConfigurationBuilder {
44      /**
45       * A test builder implementation which allows mocking the underlying reloading detector.
46       */
47      private static final class ReloadingFileBasedConfigurationBuilderTestImpl extends ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> {
48          /** The mock for the reloading detector. */
49          private final ReloadingDetector mockDetector;
50  
51          /** Stores the file handler passed to createReloadingDetector(). */
52          private FileHandler handlerForDetector;
53  
54          /**
55           * Creates a new instance of {@code ReloadingFileBasedConfigurationBuilderTestImpl} and initializes it with a mock
56           * reloading detector.
57           *
58           * @param detector the mock detector
59           */
60          public ReloadingFileBasedConfigurationBuilderTestImpl(final ReloadingDetector detector) {
61              super(PropertiesConfiguration.class);
62              mockDetector = detector;
63          }
64  
65          /**
66           * Returns the mock file handler.
67           */
68          @Override
69          protected ReloadingDetector createReloadingDetector(final FileHandler handler, final FileBasedBuilderParametersImpl fbparams) {
70              handlerForDetector = handler;
71              return mockDetector;
72          }
73  
74          /**
75           * Returns the file handler that was passed to createReloadingDetector().
76           *
77           * @return the file handler
78           */
79          public FileHandler getHandlerForDetector() {
80              return handlerForDetector;
81          }
82      }
83  
84      /**
85       * Tests whether a correct reloading detector is created if no custom factory was set.
86       */
87      @Test
88      public void testCreateReloadingDetectorDefaultFactory() throws ConfigurationException {
89          final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(
90              PropertiesConfiguration.class);
91          final FileHandler handler = new FileHandler();
92          final FileBasedBuilderParametersImpl params = new FileBasedBuilderParametersImpl();
93          final long refreshDelay = 60000L;
94          params.setReloadingRefreshDelay(refreshDelay);
95          final FileHandlerReloadingDetector detector = (FileHandlerReloadingDetector) builder.createReloadingDetector(handler, params);
96          assertSame(handler, detector.getFileHandler());
97          assertEquals(refreshDelay, detector.getRefreshDelay());
98      }
99  
100     /**
101      * Tests whether a custom reloading detector factory can be installed.
102      */
103     @Test
104     public void testCreateReloadingDetectoryCustomFactory() throws ConfigurationException {
105         final ReloadingDetector detector = mock(ReloadingDetector.class);
106         final ReloadingDetectorFactory factory = mock(ReloadingDetectorFactory.class);
107         final FileHandler handler = new FileHandler();
108         final FileBasedBuilderParametersImpl params = new FileBasedBuilderParametersImpl();
109 
110         when(factory.createReloadingDetector(handler, params)).thenReturn(detector);
111 
112         params.setReloadingDetectorFactory(factory);
113         final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(
114             PropertiesConfiguration.class);
115         assertSame(detector, builder.createReloadingDetector(handler, params));
116 
117         verify(factory).createReloadingDetector(handler, params);
118         verifyNoMoreInteractions(factory);
119     }
120 
121     /**
122      * Tests whether a configuration can be created if no location is set. This tests also ensures that the super
123      * constructor is called correctly.
124      */
125     @Test
126     public void testGetConfigurationNoLocation() throws ConfigurationException {
127         final Map<String, Object> params = new HashMap<>();
128         params.put("throwExceptionOnMissing", Boolean.TRUE);
129         final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(
130             PropertiesConfiguration.class, params);
131         final PropertiesConfiguration conf = builder.getConfiguration();
132         assertTrue(conf.isThrowExceptionOnMissing());
133         assertTrue(conf.isEmpty());
134     }
135 
136     /**
137      * Tests whether the allowFailOnInit flag is correctly initialized.
138      */
139     @Test
140     public void testInitAllowFailOnInitFlag() {
141         final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(
142             PropertiesConfiguration.class, null, true);
143         assertTrue(builder.isAllowFailOnInit());
144     }
145 
146     /**
147      * Tests whether this builder reacts on events fired by the reloading controller.
148      */
149     @Test
150     public void testReloadingControllerEvents() throws ConfigurationException {
151         final ReloadingDetector detector = mock(ReloadingDetector.class);
152 
153         when(detector.isReloadingRequired()).thenReturn(Boolean.TRUE);
154 
155         final ReloadingFileBasedConfigurationBuilderTestImpl builder = new ReloadingFileBasedConfigurationBuilderTestImpl(detector);
156         final BuilderEventListenerImpl listener = new BuilderEventListenerImpl();
157         builder.addEventListener(ConfigurationBuilderEvent.RESET, listener);
158         builder.getConfiguration();
159         builder.getReloadingController().checkForReloading(null);
160         listener.nextEvent(ConfigurationBuilderEvent.RESET);
161         listener.assertNoMoreEvents();
162 
163         verify(detector).isReloadingRequired();
164         verifyNoMoreInteractions(detector);
165     }
166 
167     /**
168      * Tests the isReloadingRequired() implementation of the detector associated with the reloading controller.
169      */
170     @Test
171     public void testReloadingDetectorIsReloadingRequired() throws ConfigurationException {
172         final ReloadingDetector detector = mock(ReloadingDetector.class);
173 
174         when(detector.isReloadingRequired()).thenReturn(Boolean.TRUE, Boolean.FALSE);
175 
176         final ReloadingFileBasedConfigurationBuilderTestImpl builder = new ReloadingFileBasedConfigurationBuilderTestImpl(detector);
177         builder.getConfiguration();
178         final ReloadingDetector ctrlDetector = builder.getReloadingController().getDetector();
179         assertTrue(ctrlDetector.isReloadingRequired());
180         assertFalse(ctrlDetector.isReloadingRequired());
181         assertSame(builder.getFileHandler(), builder.getHandlerForDetector());
182 
183         verify(detector, times(2)).isReloadingRequired();
184         verifyNoMoreInteractions(detector);
185     }
186 
187     /**
188      * Tests the behavior of the reloading detector if no underlying detector is available.
189      */
190     @Test
191     public void testReloadingDetectorNoFileHandler() {
192         final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder = new ReloadingFileBasedConfigurationBuilder<>(
193             PropertiesConfiguration.class);
194         final ReloadingDetector ctrlDetector = builder.getReloadingController().getDetector();
195         ctrlDetector.reloadingPerformed();
196         assertFalse(ctrlDetector.isReloadingRequired());
197     }
198 
199     /**
200      * Tests the reloadingPerformed() implementation of the detector associated with the reloading controller.
201      */
202     @Test
203     public void testReloadingDetectorReloadingPerformed() throws ConfigurationException {
204         final ReloadingDetector detector = mock(ReloadingDetector.class);
205         final ReloadingFileBasedConfigurationBuilderTestImpl builder = new ReloadingFileBasedConfigurationBuilderTestImpl(detector);
206         builder.getConfiguration();
207         final ReloadingDetector ctrlDetector = builder.getReloadingController().getDetector();
208         ctrlDetector.reloadingPerformed();
209 
210         verify(detector).reloadingPerformed();
211         verifyNoMoreInteractions(detector);
212     }
213 
214     /**
215      * Tests whether the controller's reloading state is reset when a new result configuration is created.
216      */
217     @Test
218     public void testResetReloadingStateInGetConfiguration() throws ConfigurationException {
219         final ReloadingDetector detector = mock(ReloadingDetector.class);
220 
221         when(detector.isReloadingRequired()).thenReturn(Boolean.TRUE);
222 
223         final ReloadingFileBasedConfigurationBuilderTestImpl builder = new ReloadingFileBasedConfigurationBuilderTestImpl(detector);
224         final PropertiesConfiguration config1 = builder.getConfiguration();
225         builder.getReloadingController().checkForReloading(null);
226         final PropertiesConfiguration config2 = builder.getConfiguration();
227         assertNotSame(config1, config2);
228         assertFalse(builder.getReloadingController().isInReloadingState());
229 
230         verify(detector).isReloadingRequired();
231         verify(detector).reloadingPerformed();
232         verifyNoMoreInteractions(detector);
233     }
234 }