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    *     https://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  
18  package org.apache.commons.configuration2;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  import static org.mockito.Mockito.mock;
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.Collections;
31  
32  import org.apache.commons.configuration2.SynchronizerTestImpl.Methods;
33  import org.apache.commons.configuration2.io.FileHandler;
34  import org.apache.commons.configuration2.sync.LockMode;
35  import org.apache.commons.configuration2.sync.NoOpSynchronizer;
36  import org.junit.jupiter.api.BeforeEach;
37  import org.junit.jupiter.api.Test;
38  import org.mockito.ArgumentMatchers;
39  
40  /**
41   * A test class for the synchronization capabilities of {@code AbstractConfiguration}. This class mainly checks the collaboration between a configuration object
42   * and its {@code Synchronizer}.
43   */
44  public class TestAbstractConfigurationSynchronization {
45  
46      /** Constant for the test property accessed by all tests. */
47      private static final String PROP = "configuration.loaded";
48  
49      /**
50       * Prepares a mock configuration for a copy operation.
51       *
52       * @return the mock configuration
53       */
54      private static Configuration prepareConfigurationMockForCopy() {
55          final Configuration config2 = mock(Configuration.class);
56          when(config2.getKeys()).thenReturn(Collections.<String>emptySet().iterator());
57          return config2;
58      }
59  
60      /**
61       * Verifies a mock configuration after a copy operation.
62       *
63       * @param mock the mock configuration
64       */
65      private static void verifyConfigurationMockAfterCopy(final Configuration mock) {
66          verify(mock).lock(LockMode.READ);
67          verify(mock).forEach(ArgumentMatchers.any());
68          verify(mock).unlock(LockMode.READ);
69      }
70  
71      /** The synchronizer used for testing. */
72      private SynchronizerTestImpl sync;
73  
74      /** A test configuration. */
75      private AbstractConfiguration config;
76  
77      @BeforeEach
78      public void setUp() throws Exception {
79          // any concrete class will do
80          final PropertiesConfiguration c = new PropertiesConfiguration();
81          new FileHandler(c).load(ConfigurationAssert.getTestFile("test.properties"));
82          sync = new SynchronizerTestImpl();
83          c.setSynchronizer(sync);
84          config = c;
85      }
86  
87      /**
88       * Tests the correct synchronization of addProperty().
89       */
90      @Test
91      void testAddPropertySynchronized() {
92          config.addProperty(PROP, "of course");
93          sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
94      }
95  
96      /**
97       * Tests whether the append() method uses synchronization.
98       */
99      @Test
100     void testAppendSynchronized() {
101         final Configuration config2 = prepareConfigurationMockForCopy();
102         config.append(config2);
103         verifyConfigurationMockAfterCopy(config2);
104         verifyNoMoreInteractions(config2);
105     }
106 
107     /**
108      * Tests the correct synchronization of clearProperty().
109      */
110     @Test
111     void testClearPropertySynchronized() {
112         config.clearProperty(PROP);
113         sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
114     }
115 
116     /**
117      * Tests the correct synchronization of clear().
118      */
119     @Test
120     void testClearSynchronized() {
121         config.clear();
122         sync.verifyStart(Methods.BEGIN_WRITE);
123         sync.verifyEnd(Methods.END_WRITE);
124     }
125 
126     /**
127      * Tests whether containsKey() is correctly synchronized.
128      */
129     @Test
130     void testContainsKeySychronized() {
131         assertTrue(config.containsKey(PROP));
132         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
133     }
134 
135     /**
136      * Tests whether the copy() method uses synchronization.
137      */
138     @Test
139     void testCopySynchronized() {
140         final Configuration config2 = prepareConfigurationMockForCopy();
141         config.copy(config2);
142         verifyConfigurationMockAfterCopy(config2);
143         verifyNoMoreInteractions(config2);
144     }
145 
146     /**
147      * Tests the Synchronizer used by default.
148      */
149     @Test
150     void testDefaultSynchronizer() {
151         assertSame(NoOpSynchronizer.INSTANCE, new PropertiesConfiguration().getSynchronizer());
152     }
153 
154     /**
155      * Tests whether getKeys(String prefix) is correctly synchronized.
156      */
157     @Test
158     void testGetKeysPrefixSynchronized() {
159         config.getKeys("test");
160         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
161     }
162 
163     /**
164      * Tests whether getKeys() is correctly synchronized.
165      */
166     @Test
167     void testGetKeysSynchronized() {
168         assertTrue(config.getKeys().hasNext());
169         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
170     }
171 
172     /**
173      * Tests whether read access to properties is synchronized.
174      */
175     @Test
176     void testGetPropertySynchronized() {
177         assertEquals("true", config.getProperty(PROP));
178         assertTrue(config.getBoolean(PROP));
179         sync.verify(Methods.BEGIN_READ, Methods.END_READ, Methods.BEGIN_READ, Methods.END_READ);
180     }
181 
182     /**
183      * Tests whether isEmpty() is correctly synchronized.
184      */
185     @Test
186     void testIsEmptySynchronized() {
187         assertFalse(config.isEmpty());
188         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
189     }
190 
191     /**
192      * Tests lock() with a null argument.
193      */
194     @Test
195     void testLockNull() {
196         assertThrows(NullPointerException.class, () -> config.lock(null));
197     }
198 
199     /**
200      * Tests whether a read lock can be obtained.
201      */
202     @Test
203     void testLockRead() {
204         config.lock(LockMode.READ);
205         sync.verify(Methods.BEGIN_READ);
206     }
207 
208     /**
209      * Tests whether a write lock can be obtained.
210      */
211     @Test
212     void testLockWrite() {
213         config.lock(LockMode.WRITE);
214         sync.verify(Methods.BEGIN_WRITE);
215     }
216 
217     /**
218      * Tests the correct synchronization of setProperty().
219      */
220     @Test
221     void testSetPropertySynchronized() {
222         config.setProperty(PROP, "yes");
223         sync.verifyStart(Methods.BEGIN_WRITE);
224         sync.verifyEnd(Methods.END_WRITE);
225     }
226 
227     /**
228      * Tests whether size() is correctly synchronized.
229      */
230     @Test
231     void testSizeSynchronized() {
232         assertFalse(config.isEmpty());
233         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
234     }
235 
236     /**
237      * Tests synchronization of subset().
238      */
239     @Test
240     void testSubsetSynchronized() {
241         final AbstractConfiguration subset = (AbstractConfiguration) config.subset("configuration");
242         sync.verify();
243         assertEquals(NoOpSynchronizer.INSTANCE, subset.getSynchronizer());
244     }
245 
246     /**
247      * Tests whether a read lock can be released.
248      */
249     @Test
250     void testUnlockRead() {
251         config.unlock(LockMode.READ);
252         sync.verify(Methods.END_READ);
253     }
254 
255     /**
256      * Tests whether a write lock can be released.
257      */
258     @Test
259     void testUnlockWrite() {
260         config.unlock(LockMode.WRITE);
261         sync.verify(Methods.END_WRITE);
262     }
263 }