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  
18  package org.apache.commons.configuration2;
19  
20  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
24  import static org.junit.jupiter.api.Assertions.assertNotNull;
25  import static org.junit.jupiter.api.Assertions.assertNull;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.util.Hashtable;
29  import java.util.Iterator;
30  import java.util.Properties;
31  
32  import javax.naming.Context;
33  import javax.naming.InitialContext;
34  import javax.naming.NameNotFoundException;
35  import javax.naming.NamingException;
36  
37  import org.apache.commons.configuration2.event.ConfigurationErrorEvent;
38  import org.apache.commons.configuration2.event.ErrorListenerTestImpl;
39  import org.apache.commons.configuration2.event.EventListener;
40  import org.apache.commons.configuration2.event.EventType;
41  import org.junit.jupiter.api.AfterEach;
42  import org.junit.jupiter.api.BeforeEach;
43  import org.junit.jupiter.api.Test;
44  
45  /**
46   * Test to see if the JNDIConfiguration works properly.
47   */
48  public class TestJNDIConfiguration {
49  
50      /**
51       * A special JNDI configuration implementation that can be configured to throw an exception when accessing the base
52       * context. Used for testing the exception handling.
53       */
54      public static class PotentialErrorJNDIConfiguration extends JNDIConfiguration {
55          /** An exception to be thrown by getBaseContext(). */
56          private NamingException exception;
57  
58          public PotentialErrorJNDIConfiguration(final Context ctx) {
59              super(ctx);
60          }
61  
62          /**
63           * Returns the JNDI context. Optionally throws an exception.
64           */
65          @Override
66          public Context getBaseContext() throws NamingException {
67              if (exception != null) {
68                  throw exception;
69              }
70              return super.getBaseContext();
71          }
72  
73          /**
74           * Prepares this object to throw a standard exception when the JNDI context is queried.
75           */
76          public void installException() {
77              installException(new NamingException("Simulated JNDI exception!"));
78          }
79  
80          /**
81           * Prepares this object to throw an exception when the JNDI context is queried.
82           *
83           * @param nex the exception to be thrown
84           */
85          public void installException(final NamingException nex) {
86              exception = nex;
87          }
88      }
89  
90      public static final String CONTEXT_FACTORY = MockInitialContextFactory.class.getName();
91      private PotentialErrorJNDIConfiguration conf;
92  
93      private NonStringTestHolder nonStringTestHolder;
94  
95      /** A test error listener for counting internal errors. */
96      private ErrorListenerTestImpl listener;
97  
98      /**
99       * Tests whether the expected error events have been received.
100      *
101      * @param type the expected event type
102      * @param opEventType the event type of the failed operation
103      * @param propName the name of the property
104      * @param propValue the property value
105      */
106     private void checkErrorListener(final EventType<? extends ConfigurationErrorEvent> type, final EventType<?> opEventType, final String propName,
107         final Object propValue) {
108         final Throwable exception = listener.checkEvent(type, opEventType, propName, propValue);
109         assertInstanceOf(NamingException.class, exception);
110         listener = null;
111     }
112 
113     @BeforeEach
114     public void setUp() throws Exception {
115 
116         System.setProperty("java.naming.factory.initial", CONTEXT_FACTORY);
117 
118         final Properties props = new Properties();
119         props.put("java.naming.factory.initial", CONTEXT_FACTORY);
120         final Context ctx = new InitialContext(props);
121         conf = new PotentialErrorJNDIConfiguration(ctx);
122 
123         nonStringTestHolder = new NonStringTestHolder();
124         nonStringTestHolder.setConfiguration(conf);
125 
126         listener = new ErrorListenerTestImpl(conf);
127         conf.addEventListener(ConfigurationErrorEvent.ANY, listener);
128     }
129 
130     /**
131      * Configures the test config to throw an exception.
132      */
133     private PotentialErrorJNDIConfiguration setUpErrorConfig() {
134         conf.installException();
135         // remove log error listener to avoid output in tests
136         final Iterator<EventListener<? super ConfigurationErrorEvent>> iterator = conf.getEventListeners(ConfigurationErrorEvent.ANY).iterator();
137         conf.removeEventListener(ConfigurationErrorEvent.ANY, iterator.next());
138         return conf;
139     }
140 
141     /**
142      * Clears the test environment. If an error listener is defined, checks whether no error event was received.
143      */
144     @AfterEach
145     public void tearDown() throws Exception {
146         if (listener != null) {
147             listener.done();
148         }
149     }
150 
151     @Test
152     public void testBoolean() throws Exception {
153         nonStringTestHolder.testBoolean();
154     }
155 
156     @Test
157     public void testBooleanDefaultValue() throws Exception {
158         nonStringTestHolder.testBooleanDefaultValue();
159     }
160 
161     @Test
162     public void testByte() throws Exception {
163         nonStringTestHolder.testByte();
164     }
165 
166     @Test
167     public void testChangePrefix() {
168         assertEquals("true", conf.getString("test.boolean"));
169         assertNull(conf.getString("boolean"));
170 
171         // change the prefix
172         conf.setPrefix("test");
173         assertNull(conf.getString("test.boolean"));
174         assertEquals("true", conf.getString("boolean"));
175     }
176 
177     @Test
178     public void testConstructor() throws Exception {
179         // test the constructor accepting a context
180         JNDIConfiguration c = new JNDIConfiguration(new InitialContext());
181 
182         assertEquals("true", c.getString("test.boolean"));
183 
184         // test the constructor accepting a context and a prefix
185         c = new JNDIConfiguration(new InitialContext(), "test");
186 
187         assertEquals("true", c.getString("boolean"));
188     }
189 
190     @Test
191     public void testContainsKey() {
192         final String key = "test.boolean";
193         assertTrue(conf.containsKey(key));
194 
195         conf.clearProperty(key);
196         assertFalse(conf.containsKey(key));
197     }
198 
199     /**
200      * Tests handling of errors in the containsKey() method.
201      */
202     @Test
203     public void testContainsKeyError() {
204         assertFalse(setUpErrorConfig().containsKey("key"));
205         checkErrorListener(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, "key", null);
206     }
207 
208     @Test
209     public void testDouble() throws Exception {
210         nonStringTestHolder.testDouble();
211     }
212 
213     @Test
214     public void testDoubleDefaultValue() throws Exception {
215         nonStringTestHolder.testDoubleDefaultValue();
216     }
217 
218     @Test
219     public void testFloat() throws Exception {
220         nonStringTestHolder.testFloat();
221     }
222 
223     @Test
224     public void testFloatDefaultValue() throws Exception {
225         nonStringTestHolder.testFloatDefaultValue();
226     }
227 
228     /**
229      * Tests handling of errors in getKeys().
230      */
231     @Test
232     public void testGetKeysError() {
233         assertFalse(setUpErrorConfig().getKeys().hasNext());
234         checkErrorListener(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null);
235     }
236 
237     /**
238      * Tests getKeys() if no data is found. This should not cause a problem and not notify the error listeners.
239      */
240     @Test
241     public void testGetKeysNoData() {
242         conf.installException(new NameNotFoundException("Test exception"));
243         assertFalse(conf.getKeys().hasNext());
244         listener.done();
245     }
246 
247     /**
248      * Tests the getKeys() method when there are cycles in the tree.
249      */
250     @Test
251     public void testGetKeysWithCycles() throws NamingException {
252         final Hashtable<Object, Object> env = new Hashtable<>();
253         env.put(MockInitialContextFactory.PROP_CYCLES, Boolean.TRUE);
254         final InitialContext initCtx = new InitialContext(env);
255         final JNDIConfiguration c = new JNDIConfiguration(initCtx);
256         assertDoesNotThrow(() -> c.getKeys("cycle"));
257     }
258 
259     /**
260      * Tests handling of errors in getProperty().
261      */
262     @Test
263     public void testGetPropertyError() {
264         assertNull(setUpErrorConfig().getProperty("key"));
265         checkErrorListener(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, "key", null);
266     }
267 
268     @Test
269     public void testInteger() throws Exception {
270         nonStringTestHolder.testInteger();
271     }
272 
273     @Test
274     public void testIntegerDefaultValue() throws Exception {
275         nonStringTestHolder.testIntegerDefaultValue();
276     }
277 
278     /**
279      * Tests handling of errors in isEmpty().
280      */
281     @Test
282     public void testIsEmptyError() throws Exception {
283         assertTrue(setUpErrorConfig().isEmpty());
284         checkErrorListener(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null);
285     }
286 
287     @Test
288     public void testListMissing() throws Exception {
289         nonStringTestHolder.testListMissing();
290     }
291 
292     /**
293      * Tests whether a JNDI configuration registers an error log listener.
294      */
295     @Test
296     public void testLogListener() throws NamingException {
297         final JNDIConfiguration c = new JNDIConfiguration();
298         assertEquals(1, c.getEventListeners(ConfigurationErrorEvent.ANY).size());
299     }
300 
301     @Test
302     public void testLong() throws Exception {
303         nonStringTestHolder.testLong();
304     }
305 
306     @Test
307     public void testLongDefaultValue() throws Exception {
308         nonStringTestHolder.testLongDefaultValue();
309     }
310 
311     @Test
312     public void testProperties() throws Exception {
313         final Object o = conf.getProperty("test.boolean");
314         assertNotNull(o);
315         assertEquals("true", o.toString());
316     }
317 
318     @Test
319     public void testResetRemovedProperties() throws Exception {
320         assertEquals("true", conf.getString("test.boolean"));
321 
322         // remove the property
323         conf.clearProperty("test.boolean");
324         assertNull(conf.getString("test.boolean"));
325 
326         // change the context
327         conf.setContext(new InitialContext());
328 
329         // get the property
330         assertEquals("true", conf.getString("test.boolean"));
331     }
332 
333     @Test
334     public void testShort() throws Exception {
335         nonStringTestHolder.testShort();
336     }
337 
338     @Test
339     public void testShortDefaultValue() throws Exception {
340         nonStringTestHolder.testShortDefaultValue();
341     }
342 
343     @Test
344     public void testSubset() throws Exception {
345         nonStringTestHolder.testSubset();
346     }
347 }