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