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