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      /** A test configuration. */
74      private AbstractConfiguration config;
75  
76      @BeforeEach
77      public void setUp() throws Exception {
78          // any concrete class will do
79          final PropertiesConfiguration c = new PropertiesConfiguration();
80          new FileHandler(c).load(ConfigurationAssert.getTestFile("test.properties"));
81          sync = new SynchronizerTestImpl();
82          c.setSynchronizer(sync);
83          config = c;
84      }
85  
86      /**
87       * Tests the correct synchronization of addProperty().
88       */
89      @Test
90      void testAddPropertySynchronized() {
91          config.addProperty(PROP, "of course");
92          sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
93      }
94  
95      /**
96       * Tests whether the append() method uses synchronization.
97       */
98      @Test
99      void testAppendSynchronized() {
100         final Configuration config2 = prepareConfigurationMockForCopy();
101         config.append(config2);
102         verifyConfigurationMockAfterCopy(config2);
103         verifyNoMoreInteractions(config2);
104     }
105 
106     /**
107      * Tests the correct synchronization of clearProperty().
108      */
109     @Test
110     void testClearPropertySynchronized() {
111         config.clearProperty(PROP);
112         sync.verify(Methods.BEGIN_WRITE, Methods.END_WRITE);
113     }
114 
115     /**
116      * Tests the correct synchronization of clear().
117      */
118     @Test
119     void testClearSynchronized() {
120         config.clear();
121         sync.verifyStart(Methods.BEGIN_WRITE);
122         sync.verifyEnd(Methods.END_WRITE);
123     }
124 
125     /**
126      * Tests whether containsKey() is correctly synchronized.
127      */
128     @Test
129     void testContainsKeySychronized() {
130         assertTrue(config.containsKey(PROP));
131         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
132     }
133 
134     /**
135      * Tests whether the copy() method uses synchronization.
136      */
137     @Test
138     void testCopySynchronized() {
139         final Configuration config2 = prepareConfigurationMockForCopy();
140         config.copy(config2);
141         verifyConfigurationMockAfterCopy(config2);
142         verifyNoMoreInteractions(config2);
143     }
144 
145     /**
146      * Tests the Synchronizer used by default.
147      */
148     @Test
149     void testDefaultSynchronizer() {
150         assertSame(NoOpSynchronizer.INSTANCE, new PropertiesConfiguration().getSynchronizer());
151     }
152 
153     /**
154      * Tests whether getKeys(String prefix) is correctly synchronized.
155      */
156     @Test
157     void testGetKeysPrefixSynchronized() {
158         config.getKeys("test");
159         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
160     }
161 
162     /**
163      * Tests whether getKeys() is correctly synchronized.
164      */
165     @Test
166     void testGetKeysSynchronized() {
167         assertTrue(config.getKeys().hasNext());
168         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
169     }
170 
171     /**
172      * Tests whether read access to properties is synchronized.
173      */
174     @Test
175     void testGetPropertySynchronized() {
176         assertEquals("true", config.getProperty(PROP));
177         assertTrue(config.getBoolean(PROP));
178         sync.verify(Methods.BEGIN_READ, Methods.END_READ, Methods.BEGIN_READ, Methods.END_READ);
179     }
180 
181     /**
182      * Tests whether isEmpty() is correctly synchronized.
183      */
184     @Test
185     void testIsEmptySynchronized() {
186         assertFalse(config.isEmpty());
187         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
188     }
189 
190     /**
191      * Tests lock() with a null argument.
192      */
193     @Test
194     void testLockNull() {
195         assertThrows(NullPointerException.class, () -> config.lock(null));
196     }
197 
198     /**
199      * Tests whether a read lock can be obtained.
200      */
201     @Test
202     void testLockRead() {
203         config.lock(LockMode.READ);
204         sync.verify(Methods.BEGIN_READ);
205     }
206 
207     /**
208      * Tests whether a write lock can be obtained.
209      */
210     @Test
211     void testLockWrite() {
212         config.lock(LockMode.WRITE);
213         sync.verify(Methods.BEGIN_WRITE);
214     }
215 
216     /**
217      * Tests the correct synchronization of setProperty().
218      */
219     @Test
220     void testSetPropertySynchronized() {
221         config.setProperty(PROP, "yes");
222         sync.verifyStart(Methods.BEGIN_WRITE);
223         sync.verifyEnd(Methods.END_WRITE);
224     }
225 
226     /**
227      * Tests whether size() is correctly synchronized.
228      */
229     @Test
230     void testSizeSynchronized() {
231         assertFalse(config.isEmpty());
232         sync.verify(Methods.BEGIN_READ, Methods.END_READ);
233     }
234 
235     /**
236      * Tests synchronization of subset().
237      */
238     @Test
239     void testSubsetSynchronized() {
240         final AbstractConfiguration subset = (AbstractConfiguration) config.subset("configuration");
241         sync.verify();
242         assertEquals(NoOpSynchronizer.INSTANCE, subset.getSynchronizer());
243     }
244 
245     /**
246      * Tests whether a read lock can be released.
247      */
248     @Test
249     void testUnlockRead() {
250         config.unlock(LockMode.READ);
251         sync.verify(Methods.END_READ);
252     }
253 
254     /**
255      * Tests whether a write lock can be released.
256      */
257     @Test
258     void testUnlockWrite() {
259         config.unlock(LockMode.WRITE);
260         sync.verify(Methods.END_WRITE);
261     }
262 }