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.configuration;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.sql.Connection;
25  import java.sql.SQLException;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  import javax.sql.DataSource;
30  
31  import org.junit.After;
32  import org.junit.Before;
33  import org.junit.Test;
34  
35  /**
36   * Test for database stored configurations.  Note, when running this Unit
37   * Test in Eclipse it sometimes takes a couple tries. Otherwise you may get
38   * database is already in use by another process errors.
39   *
40   * @version $Id: TestDatabaseConfiguration.java 1223016 2011-12-24 20:56:52Z oheger $
41   */
42  public class TestDatabaseConfiguration
43  {
44      /** Constant for another configuration name. */
45      private static final String CONFIG_NAME2 = "anotherTestConfig";
46  
47      /** An error listener for testing whether internal errors occurred.*/
48      private ConfigurationErrorListenerImpl listener;
49  
50      /** The test helper. */
51      private DatabaseConfigurationTestHelper helper;
52  
53      @Before
54      public void setUp() throws Exception
55      {
56          /*
57           * Thread.sleep may or may not help with the database is already in
58           * use exception.
59           */
60          //Thread.sleep(1000);
61  
62          // set up the datasource
63  
64          helper = new DatabaseConfigurationTestHelper();
65          helper.setUp();
66      }
67  
68      @After
69      public void tearDown() throws Exception
70      {
71          // if an error listener is defined, we check whether an error occurred
72          if(listener != null)
73          {
74              assertEquals("An internal error occurred", 0, listener.getErrorCount());
75          }
76          helper.tearDown();
77      }
78  
79      /**
80       * Creates a database configuration with default values.
81       *
82       * @return the configuration
83       */
84      private PotentialErrorDatabaseConfiguration setUpConfig()
85      {
86          return new PotentialErrorDatabaseConfiguration(helper.getDatasource(),
87                  DatabaseConfigurationTestHelper.TABLE,
88                  DatabaseConfigurationTestHelper.COL_KEY,
89                  DatabaseConfigurationTestHelper.COL_VALUE);
90      }
91  
92      /**
93       * Creates an error listener and adds it to the specified configuration.
94       *
95       * @param config the configuration
96       */
97      private void setUpErrorListener(PotentialErrorDatabaseConfiguration config)
98      {
99          // remove log listener to avoid exception longs
100         config.removeErrorListener(config.getErrorListeners().iterator().next());
101         listener = new ConfigurationErrorListenerImpl();
102         config.addErrorListener(listener);
103         config.failOnConnect = true;
104     }
105 
106     /**
107      * Prepares a test for a database error. Sets up a config and registers an
108      * error listener.
109      *
110      * @return the initialized configuration
111      */
112     private PotentialErrorDatabaseConfiguration setUpErrorConfig()
113     {
114         PotentialErrorDatabaseConfiguration config = setUpConfig();
115         setUpErrorListener(config);
116         return config;
117     }
118 
119     /**
120      * Checks the error listener for an expected error. The properties of the
121      * error event will be compared with the expected values.
122      *
123      * @param type the expected type of the error event
124      * @param key the expected property key
125      * @param value the expected property value
126      */
127     private void checkErrorListener(int type, String key, Object value)
128     {
129         listener.verify(type, key, value);
130         assertTrue(
131                 "Wrong event source",
132                 listener.getLastEvent().getSource() instanceof DatabaseConfiguration);
133         assertTrue("Wrong exception",
134                 listener.getLastEvent().getCause() instanceof SQLException);
135         listener = null; // mark as checked
136     }
137 
138     /**
139      * Tests the default value of the doCommits property.
140      */
141     @Test
142     public void testDoCommitsDefault()
143     {
144         DatabaseConfiguration config = new DatabaseConfiguration(helper
145                 .getDatasource(), DatabaseConfigurationTestHelper.TABLE,
146                 DatabaseConfigurationTestHelper.COL_KEY,
147                 DatabaseConfigurationTestHelper.COL_VALUE);
148         assertFalse("Wrong commits flag", config.isDoCommits());
149     }
150 
151     /**
152      * Tests the default value of the doCommits property for multiple
153      * configurations in a table.
154      */
155     @Test
156     public void testDoCommitsDefaultMulti()
157     {
158         DatabaseConfiguration config = new DatabaseConfiguration(helper
159                 .getDatasource(), DatabaseConfigurationTestHelper.TABLE,
160                 DatabaseConfigurationTestHelper.COL_NAME,
161                 DatabaseConfigurationTestHelper.COL_KEY,
162                 DatabaseConfigurationTestHelper.COL_VALUE,
163                 DatabaseConfigurationTestHelper.CONFIG_NAME);
164         assertFalse("Wrong commits flag", config.isDoCommits());
165     }
166 
167     @Test
168     public void testAddPropertyDirectSingle()
169     {
170         DatabaseConfiguration config = helper.setUpConfig();
171         config.addPropertyDirect("key", "value");
172 
173         assertTrue("missing property", config.containsKey("key"));
174     }
175 
176     /**
177      * Tests whether a commit is performed after a property was added.
178      */
179     @Test
180     public void testAddPropertyDirectCommit()
181     {
182         helper.setAutoCommit(false);
183         DatabaseConfiguration config = helper.setUpConfig();
184         config.addPropertyDirect("key", "value");
185         assertTrue("missing property", config.containsKey("key"));
186     }
187 
188     @Test
189     public void testAddPropertyDirectMultiple()
190     {
191         DatabaseConfiguration config = helper.setUpMultiConfig();
192         config.addPropertyDirect("key", "value");
193 
194         assertTrue("missing property", config.containsKey("key"));
195     }
196 
197     @Test
198     public void testAddNonStringProperty()
199     {
200         DatabaseConfiguration config = helper.setUpConfig();
201         config.addPropertyDirect("boolean", Boolean.TRUE);
202 
203         assertTrue("missing property", config.containsKey("boolean"));
204     }
205 
206     @Test
207     public void testGetPropertyDirectSingle()
208     {
209         Configuration config = setUpConfig();
210 
211         assertEquals("property1", "value1", config.getProperty("key1"));
212         assertEquals("property2", "value2", config.getProperty("key2"));
213         assertEquals("unknown property", null, config.getProperty("key3"));
214     }
215 
216     @Test
217     public void testGetPropertyDirectMultiple()
218     {
219         Configuration config = helper.setUpMultiConfig();
220 
221         assertEquals("property1", "value1", config.getProperty("key1"));
222         assertEquals("property2", "value2", config.getProperty("key2"));
223         assertEquals("unknown property", null, config.getProperty("key3"));
224     }
225 
226     @Test
227     public void testClearPropertySingle()
228     {
229         Configuration config = helper.setUpConfig();
230         config.clearProperty("key1");
231 
232         assertFalse("property not cleared", config.containsKey("key1"));
233     }
234 
235     @Test
236     public void testClearPropertyMultiple()
237     {
238         Configuration config = helper.setUpMultiConfig();
239         config.clearProperty("key1");
240 
241         assertFalse("property not cleared", config.containsKey("key1"));
242     }
243 
244     /**
245      * Tests that another configuration is not affected when clearing
246      * properties.
247      */
248     @Test
249     public void testClearPropertyMultipleOtherConfig()
250     {
251         DatabaseConfiguration config = helper.setUpMultiConfig();
252         DatabaseConfiguration config2 = helper.setUpMultiConfig(CONFIG_NAME2);
253         config2.addProperty("key1", "some test");
254         config.clearProperty("key1");
255         assertFalse("property not cleared", config.containsKey("key1"));
256         assertTrue("Property cleared in other config", config2
257                 .containsKey("key1"));
258     }
259 
260     /**
261      * Tests whether a commit is performed after a property was cleared.
262      */
263     @Test
264     public void testClearPropertyCommit()
265     {
266         helper.setAutoCommit(false);
267         Configuration config = helper.setUpConfig();
268         config.clearProperty("key1");
269         assertFalse("property not cleared", config.containsKey("key1"));
270     }
271 
272     @Test
273     public void testClearSingle()
274     {
275         Configuration config = helper.setUpConfig();
276         config.clear();
277 
278         assertTrue("configuration is not cleared", config.isEmpty());
279     }
280 
281     @Test
282     public void testClearMultiple()
283     {
284         Configuration config = helper.setUpMultiConfig();
285         config.clear();
286 
287         assertTrue("configuration is not cleared", config.isEmpty());
288     }
289 
290     /**
291      * Tests whether a commit is performed after a clear operation.
292      */
293     @Test
294     public void testClearCommit()
295     {
296         helper.setAutoCommit(false);
297         Configuration config = helper.setUpConfig();
298         config.clear();
299         assertTrue("configuration is not cleared", config.isEmpty());
300     }
301 
302     @Test
303     public void testGetKeysSingle()
304     {
305         Configuration config = setUpConfig();
306         Iterator<String> it = config.getKeys();
307 
308         assertEquals("1st key", "key1", it.next());
309         assertEquals("2nd key", "key2", it.next());
310     }
311 
312     @Test
313     public void testGetKeysMultiple()
314     {
315         Configuration config = helper.setUpMultiConfig();
316         Iterator<String> it = config.getKeys();
317 
318         assertEquals("1st key", "key1", it.next());
319         assertEquals("2nd key", "key2", it.next());
320     }
321 
322     @Test
323     public void testContainsKeySingle()
324     {
325         Configuration config = setUpConfig();
326         assertTrue("missing key1", config.containsKey("key1"));
327         assertTrue("missing key2", config.containsKey("key2"));
328     }
329 
330     @Test
331     public void testContainsKeyMultiple()
332     {
333         Configuration config = helper.setUpMultiConfig();
334         assertTrue("missing key1", config.containsKey("key1"));
335         assertTrue("missing key2", config.containsKey("key2"));
336     }
337 
338     @Test
339     public void testIsEmptySingle()
340     {
341         Configuration config1 = setUpConfig();
342         assertFalse("The configuration is empty", config1.isEmpty());
343     }
344 
345     @Test
346     public void testIsEmptyMultiple()
347     {
348         Configuration config1 = helper.setUpMultiConfig();
349         assertFalse("The configuration named 'test' is empty", config1.isEmpty());
350 
351         Configuration config2 = new DatabaseConfiguration(helper.getDatasource(), DatabaseConfigurationTestHelper.TABLE_MULTI, DatabaseConfigurationTestHelper.COL_NAME, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE, "testIsEmpty");
352         assertTrue("The configuration named 'testIsEmpty' is not empty", config2.isEmpty());
353     }
354 
355     @Test
356     public void testGetList()
357     {
358         Configuration config1 = new DatabaseConfiguration(helper.getDatasource(), "configurationList", DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE);
359         List<Object> list = config1.getList("key3");
360         assertEquals(3,list.size());
361     }
362 
363     @Test
364     public void testGetKeys()
365     {
366         Configuration config1 = new DatabaseConfiguration(helper.getDatasource(), "configurationList", DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE);
367         Iterator<String> i = config1.getKeys();
368         assertTrue(i.hasNext());
369         Object key = i.next();
370         assertEquals("key3",key.toString());
371         assertFalse(i.hasNext());
372     }
373 
374     @Test
375     public void testClearSubset()
376     {
377         Configuration config = setUpConfig();
378 
379         Configuration subset = config.subset("key1");
380         subset.clear();
381 
382         assertTrue("the subset is not empty", subset.isEmpty());
383         assertFalse("the parent configuration is empty", config.isEmpty());
384     }
385 
386     /**
387      * Tests whether the configuration has already an error listener registered
388      * that is used for logging.
389      */
390     @Test
391     public void testLogErrorListener()
392     {
393         DatabaseConfiguration config = new DatabaseConfiguration(helper.getDatasource(), DatabaseConfigurationTestHelper.TABLE, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE);
394         assertEquals("No error listener registered", 1, config.getErrorListeners().size());
395     }
396 
397     /**
398      * Tests handling of errors in getProperty().
399      */
400     @Test
401     public void testGetPropertyError()
402     {
403         setUpErrorConfig().getProperty("key1");
404         checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key1", null);
405     }
406 
407     /**
408      * Tests handling of errors in addPropertyDirect().
409      */
410     @Test
411     public void testAddPropertyError()
412     {
413         setUpErrorConfig().addProperty("key1", "value");
414         checkErrorListener(AbstractConfiguration.EVENT_ADD_PROPERTY, "key1", "value");
415     }
416 
417     /**
418      * Tests handling of errors in isEmpty().
419      */
420     @Test
421     public void testIsEmptyError()
422     {
423         assertTrue("Wrong return value for failure", setUpErrorConfig().isEmpty());
424         checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null);
425     }
426 
427     /**
428      * Tests handling of errors in containsKey().
429      */
430     @Test
431     public void testContainsKeyError()
432     {
433         assertFalse("Wrong return value for failure", setUpErrorConfig().containsKey("key1"));
434         checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key1", null);
435     }
436 
437     /**
438      * Tests handling of errors in clearProperty().
439      */
440     @Test
441     public void testClearPropertyError()
442     {
443         setUpErrorConfig().clearProperty("key1");
444         checkErrorListener(AbstractConfiguration.EVENT_CLEAR_PROPERTY, "key1", null);
445     }
446 
447     /**
448      * Tests handling of errors in clear().
449      */
450     @Test
451     public void testClearError()
452     {
453         setUpErrorConfig().clear();
454         checkErrorListener(AbstractConfiguration.EVENT_CLEAR, null, null);
455     }
456 
457     /**
458      * Tests handling of errors in getKeys().
459      */
460     @Test
461     public void testGetKeysError()
462     {
463         Iterator<String> it = setUpErrorConfig().getKeys();
464         checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null);
465         assertFalse("Iteration is not empty", it.hasNext());
466     }
467 
468     /**
469      * Tests obtaining a property as list whose value contains the list
470      * delimiter. Multiple values should be returned.
471      */
472     @Test
473     public void testGetListWithDelimiter()
474     {
475         DatabaseConfiguration config = setUpConfig();
476         config.setListDelimiter(';');
477         List<Object> values = config.getList("keyMulti");
478         assertEquals("Wrong number of list elements", 3, values.size());
479         assertEquals("Wrong list element 0", "a", values.get(0));
480         assertEquals("Wrong list element 2", "c", values.get(2));
481     }
482 
483     /**
484      * Tests obtaining a property whose value contains the list delimiter when
485      * delimiter parsing is disabled.
486      */
487     @Test
488     public void testGetListWithDelimiterParsingDisabled()
489     {
490         DatabaseConfiguration config = setUpConfig();
491         config.setListDelimiter(';');
492         config.setDelimiterParsingDisabled(true);
493         assertEquals("Wrong value of property", "a;b;c", config.getString("keyMulti"));
494     }
495 
496     /**
497      * Tests adding a property containing the list delimiter. When this property
498      * is queried multiple values should be returned.
499      */
500     @Test
501     public void testAddWithDelimiter()
502     {
503         DatabaseConfiguration config = setUpConfig();
504         config.setListDelimiter(';');
505         config.addProperty("keyList", "1;2;3");
506         String[] values = config.getStringArray("keyList");
507         assertEquals("Wrong number of property values", 3, values.length);
508         assertEquals("Wrong value at index 1", "2", values[1]);
509     }
510 
511     /**
512      * Tests setProperty() if the property value contains the list delimiter.
513      */
514     @Test
515     public void testSetPropertyWithDelimiter()
516     {
517         DatabaseConfiguration config = helper.setUpMultiConfig();
518         config.setListDelimiter(';');
519         config.setProperty("keyList", "1;2;3");
520         String[] values = config.getStringArray("keyList");
521         assertEquals("Wrong number of property values", 3, values.length);
522         assertEquals("Wrong value at index 1", "2", values[1]);
523     }
524 
525     /**
526      * A specialized database configuration implementation that can be
527      * configured to throw an exception when obtaining a connection. This way
528      * database exceptions can be simulated.
529      */
530     static class PotentialErrorDatabaseConfiguration extends DatabaseConfiguration
531     {
532         /** A flag whether a getConnection() call should fail. */
533         boolean failOnConnect;
534 
535         public PotentialErrorDatabaseConfiguration(DataSource datasource,
536                 String table, String keyColumn, String valueColumn)
537         {
538             super(datasource, table, keyColumn, valueColumn);
539         }
540 
541         @Override
542         protected Connection getConnection() throws SQLException
543         {
544             if (failOnConnect)
545             {
546                 throw new SQLException("Simulated DB error");
547             }
548             return super.getConnection();
549         }
550     }
551 }