001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.configuration; 019 020 import static org.junit.Assert.assertEquals; 021 import static org.junit.Assert.assertFalse; 022 import static org.junit.Assert.assertTrue; 023 024 import java.sql.Connection; 025 import java.sql.SQLException; 026 import java.util.Iterator; 027 import java.util.List; 028 029 import javax.sql.DataSource; 030 031 import org.junit.After; 032 import org.junit.Before; 033 import org.junit.Test; 034 035 /** 036 * Test for database stored configurations. Note, when running this Unit 037 * Test in Eclipse it sometimes takes a couple tries. Otherwise you may get 038 * database is already in use by another process errors. 039 * 040 * @version $Id: TestDatabaseConfiguration.java 1223016 2011-12-24 20:56:52Z oheger $ 041 */ 042 public class TestDatabaseConfiguration 043 { 044 /** Constant for another configuration name. */ 045 private static final String CONFIG_NAME2 = "anotherTestConfig"; 046 047 /** An error listener for testing whether internal errors occurred.*/ 048 private ConfigurationErrorListenerImpl listener; 049 050 /** The test helper. */ 051 private DatabaseConfigurationTestHelper helper; 052 053 @Before 054 public void setUp() throws Exception 055 { 056 /* 057 * Thread.sleep may or may not help with the database is already in 058 * use exception. 059 */ 060 //Thread.sleep(1000); 061 062 // set up the datasource 063 064 helper = new DatabaseConfigurationTestHelper(); 065 helper.setUp(); 066 } 067 068 @After 069 public void tearDown() throws Exception 070 { 071 // if an error listener is defined, we check whether an error occurred 072 if(listener != null) 073 { 074 assertEquals("An internal error occurred", 0, listener.getErrorCount()); 075 } 076 helper.tearDown(); 077 } 078 079 /** 080 * Creates a database configuration with default values. 081 * 082 * @return the configuration 083 */ 084 private PotentialErrorDatabaseConfiguration setUpConfig() 085 { 086 return new PotentialErrorDatabaseConfiguration(helper.getDatasource(), 087 DatabaseConfigurationTestHelper.TABLE, 088 DatabaseConfigurationTestHelper.COL_KEY, 089 DatabaseConfigurationTestHelper.COL_VALUE); 090 } 091 092 /** 093 * Creates an error listener and adds it to the specified configuration. 094 * 095 * @param config the configuration 096 */ 097 private void setUpErrorListener(PotentialErrorDatabaseConfiguration config) 098 { 099 // 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 }