1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration;
18
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.util.Collection;
24 import java.util.Set;
25
26 import org.apache.commons.configuration.event.ConfigurationEvent;
27 import org.apache.commons.configuration.event.ConfigurationListener;
28 import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
29 import org.apache.commons.configuration.tree.NodeCombiner;
30 import org.apache.commons.configuration.tree.UnionCombiner;
31
32 import junit.framework.Assert;
33 import junit.framework.TestCase;
34
35 /***
36 * Test class for CombinedConfiguration.
37 *
38 * @version $Id: TestCombinedConfiguration.java 484692 2006-12-08 18:30:15Z oheger $
39 */
40 public class TestCombinedConfiguration extends TestCase
41 {
42 /*** Constant for the name of a sub configuration. */
43 static final String TEST_NAME = "SUBCONFIG";
44
45 /*** Constant for a test key. */
46 static final String TEST_KEY = "test.value";
47
48 /*** The configuration to be tested. */
49 CombinedConfiguration config;
50
51 /*** The test event listener. */
52 CombinedListener listener;
53
54 protected void setUp() throws Exception
55 {
56 super.setUp();
57 config = new CombinedConfiguration();
58 listener = new CombinedListener();
59 config.addConfigurationListener(listener);
60 }
61
62 /***
63 * Tests accessing a newly created combined configuration.
64 */
65 public void testInit()
66 {
67 assertEquals("Already configurations contained", 0, config
68 .getNumberOfConfigurations());
69 assertTrue("Set of names is not empty", config.getConfigurationNames()
70 .isEmpty());
71 assertTrue("Wrong node combiner",
72 config.getNodeCombiner() instanceof UnionCombiner);
73 assertNull("Test config was found", config.getConfiguration(TEST_NAME));
74 assertFalse("Force reload check flag is set", config.isForceReloadCheck());
75 }
76
77 /***
78 * Tests adding a configuration (without further information).
79 */
80 public void testAddConfiguration()
81 {
82 AbstractConfiguration c = setUpTestConfiguration();
83 config.addConfiguration(c);
84 checkAddConfig(c);
85 assertEquals("Wrong number of configs", 1, config
86 .getNumberOfConfigurations());
87 assertTrue("Name list is not empty", config.getConfigurationNames()
88 .isEmpty());
89 assertSame("Added config not found", c, config.getConfiguration(0));
90 assertTrue("Wrong property value", config.getBoolean(TEST_KEY));
91 listener.checkEvent(1, 0);
92 }
93
94 /***
95 * Tests adding a configuration with a name.
96 */
97 public void testAddConfigurationWithName()
98 {
99 AbstractConfiguration c = setUpTestConfiguration();
100 config.addConfiguration(c, TEST_NAME);
101 checkAddConfig(c);
102 assertEquals("Wrong number of configs", 1, config
103 .getNumberOfConfigurations());
104 assertSame("Added config not found", c, config.getConfiguration(0));
105 assertSame("Added config not found by name", c, config
106 .getConfiguration(TEST_NAME));
107 Set names = config.getConfigurationNames();
108 assertEquals("Wrong number of config names", 1, names.size());
109 assertTrue("Name not found", names.contains(TEST_NAME));
110 assertTrue("Wrong property value", config.getBoolean(TEST_KEY));
111 listener.checkEvent(1, 0);
112 }
113
114 /***
115 * Tests adding a configuration with a name when this name already exists.
116 * This should cause an exception.
117 */
118 public void testAddConfigurationWithNameTwice()
119 {
120 config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
121 try
122 {
123 config.addConfiguration(setUpTestConfiguration(), TEST_NAME,
124 "prefix");
125 fail("Could add config with same name!");
126 }
127 catch (ConfigurationRuntimeException cex)
128 {
129
130 }
131 }
132
133 /***
134 * Tests adding a configuration and specifying an at position.
135 */
136 public void testAddConfigurationAt()
137 {
138 AbstractConfiguration c = setUpTestConfiguration();
139 config.addConfiguration(c, null, "my");
140 checkAddConfig(c);
141 assertTrue("Wrong property value", config.getBoolean("my." + TEST_KEY));
142 }
143
144 /***
145 * Tests adding a configuration with a complex at position. Here the at path
146 * contains a dot, which must be escaped.
147 */
148 public void testAddConfigurationComplexAt()
149 {
150 AbstractConfiguration c = setUpTestConfiguration();
151 config.addConfiguration(c, null, "This..is.a.complex");
152 checkAddConfig(c);
153 assertTrue("Wrong property value", config
154 .getBoolean("This..is.a.complex." + TEST_KEY));
155 }
156
157 /***
158 * Checks if a configuration was correctly added to the combined config.
159 *
160 * @param c the config to check
161 */
162 private void checkAddConfig(AbstractConfiguration c)
163 {
164 Collection listeners = c.getConfigurationListeners();
165 assertEquals("Wrong number of configuration listeners", 1, listeners
166 .size());
167 assertTrue("Combined config is no listener", listeners.contains(config));
168 }
169
170 /***
171 * Tests adding a null configuration. This should cause an exception to be
172 * thrown.
173 */
174 public void testAddNullConfiguration()
175 {
176 try
177 {
178 config.addConfiguration(null);
179 fail("Could add null configuration!");
180 }
181 catch (IllegalArgumentException iex)
182 {
183
184 }
185 }
186
187 /***
188 * Tests accessing properties if no configurations have been added.
189 */
190 public void testAccessPropertyEmpty()
191 {
192 assertFalse("Found a key", config.containsKey(TEST_KEY));
193 assertNull("Key has a value", config.getString("test.comment"));
194 assertTrue("Config is not empty", config.isEmpty());
195 }
196
197 /***
198 * Tests accessing properties if multiple configurations have been added.
199 */
200 public void testAccessPropertyMulti()
201 {
202 config.addConfiguration(setUpTestConfiguration());
203 config.addConfiguration(setUpTestConfiguration(), null, "prefix1");
204 config.addConfiguration(setUpTestConfiguration(), null, "prefix2");
205 assertTrue("Prop1 not found", config.getBoolean(TEST_KEY));
206 assertTrue("Prop 2 not found", config.getBoolean("prefix1." + TEST_KEY));
207 assertTrue("Prop 3 not found", config.getBoolean("prefix2." + TEST_KEY));
208 assertFalse("Configuration is empty", config.isEmpty());
209 listener.checkEvent(3, 0);
210 }
211
212 /***
213 * Tests removing a configuration.
214 */
215 public void testRemoveConfiguration()
216 {
217 AbstractConfiguration c = setUpTestConfiguration();
218 config.addConfiguration(c);
219 checkAddConfig(c);
220 assertTrue("Config could not be removed", config.removeConfiguration(c));
221 checkRemoveConfig(c);
222 }
223
224 /***
225 * Tests removing a configuration by index.
226 */
227 public void testRemoveConfigurationAt()
228 {
229 AbstractConfiguration c = setUpTestConfiguration();
230 config.addConfiguration(c);
231 assertSame("Wrong config removed", c, config.removeConfigurationAt(0));
232 checkRemoveConfig(c);
233 }
234
235 /***
236 * Tests removing a configuration by name.
237 */
238 public void testRemoveConfigurationByName()
239 {
240 AbstractConfiguration c = setUpTestConfiguration();
241 config.addConfiguration(c, TEST_NAME);
242 assertSame("Wrong config removed", c, config
243 .removeConfiguration(TEST_NAME));
244 checkRemoveConfig(c);
245 }
246
247 /***
248 * Tests removing a configuration with a name.
249 */
250 public void testRemoveNamedConfiguration()
251 {
252 AbstractConfiguration c = setUpTestConfiguration();
253 config.addConfiguration(c, TEST_NAME);
254 config.removeConfiguration(c);
255 checkRemoveConfig(c);
256 }
257
258 /***
259 * Tests removing a named configuration by index.
260 */
261 public void testRemoveNamedConfigurationAt()
262 {
263 AbstractConfiguration c = setUpTestConfiguration();
264 config.addConfiguration(c, TEST_NAME);
265 assertSame("Wrong config removed", c, config.removeConfigurationAt(0));
266 checkRemoveConfig(c);
267 }
268
269 /***
270 * Tests removing a configuration that was not added prior.
271 */
272 public void testRemoveNonContainedConfiguration()
273 {
274 assertFalse("Could remove non contained config", config
275 .removeConfiguration(setUpTestConfiguration()));
276 listener.checkEvent(0, 0);
277 }
278
279 /***
280 * Tests removing a configuration by name, which is not contained.
281 */
282 public void testRemoveConfigurationByUnknownName()
283 {
284 assertNull("Could remove configuration by unknown name", config
285 .removeConfiguration("unknownName"));
286 listener.checkEvent(0, 0);
287 }
288
289 /***
290 * Tests whether a configuration was completely removed.
291 *
292 * @param c the removed configuration
293 */
294 private void checkRemoveConfig(AbstractConfiguration c)
295 {
296 assertTrue("Listener was not removed", c.getConfigurationListeners()
297 .isEmpty());
298 assertEquals("Wrong number of contained configs", 0, config
299 .getNumberOfConfigurations());
300 assertTrue("Name was not removed", config.getConfigurationNames()
301 .isEmpty());
302 listener.checkEvent(2, 0);
303 }
304
305 /***
306 * Tests if an update of a contained configuration leeds to an invalidation
307 * of the combined configuration.
308 */
309 public void testUpdateContainedConfiguration()
310 {
311 AbstractConfiguration c = setUpTestConfiguration();
312 config.addConfiguration(c);
313 c.addProperty("test.otherTest", "yes");
314 assertEquals("New property not found", "yes", config
315 .getString("test.otherTest"));
316 listener.checkEvent(3, 0);
317 }
318
319 /***
320 * Tests if setting a node combiner causes an invalidation.
321 */
322 public void testSetNodeCombiner()
323 {
324 NodeCombiner combiner = new UnionCombiner();
325 config.setNodeCombiner(combiner);
326 assertSame("Node combiner was not set", combiner, config
327 .getNodeCombiner());
328 listener.checkEvent(1, 0);
329 }
330
331 /***
332 * Tests setting a null node combiner. This should cause an exception.
333 */
334 public void testSetNullNodeCombiner()
335 {
336 try
337 {
338 config.setNodeCombiner(null);
339 fail("Could set null node combiner!");
340 }
341 catch (IllegalArgumentException iex)
342 {
343
344 }
345 }
346
347 /***
348 * Tests cloning a combined configuration.
349 */
350 public void testClone()
351 {
352 config.addConfiguration(setUpTestConfiguration());
353 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2");
354 config.addConfiguration(new PropertiesConfiguration(), "props");
355
356 CombinedConfiguration cc2 = (CombinedConfiguration) config.clone();
357 assertEquals("Wrong number of contained configurations", config
358 .getNumberOfConfigurations(), cc2.getNumberOfConfigurations());
359 assertSame("Wrong node combiner", config.getNodeCombiner(), cc2
360 .getNodeCombiner());
361 assertEquals("Wrong number of names", config.getConfigurationNames()
362 .size(), cc2.getConfigurationNames().size());
363 assertTrue("Event listeners were cloned", cc2
364 .getConfigurationListeners().isEmpty());
365
366 StrictConfigurationComparator comp = new StrictConfigurationComparator();
367 for (int i = 0; i < config.getNumberOfConfigurations(); i++)
368 {
369 assertNotSame("Configuration at " + i + " was not cloned", config
370 .getConfiguration(i), cc2.getConfiguration(i));
371 assertEquals("Wrong config class at " + i, config.getConfiguration(
372 i).getClass(), cc2.getConfiguration(i).getClass());
373 assertTrue("Configs not equal at " + i, comp.compare(config
374 .getConfiguration(i), cc2.getConfiguration(i)));
375 }
376
377 assertTrue("Combined configs not equal", comp.compare(config, cc2));
378 }
379
380 /***
381 * Tests if the cloned configuration is decoupled from the original.
382 */
383 public void testCloneModify()
384 {
385 config.addConfiguration(setUpTestConfiguration(), TEST_NAME);
386 CombinedConfiguration cc2 = (CombinedConfiguration) config.clone();
387 assertTrue("Name is missing", cc2.getConfigurationNames().contains(
388 TEST_NAME));
389 cc2.removeConfiguration(TEST_NAME);
390 assertFalse("Names in original changed", config.getConfigurationNames()
391 .isEmpty());
392 }
393
394 /***
395 * Tests clearing a combined configuration. This should remove all contained
396 * configurations.
397 */
398 public void testClear()
399 {
400 config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "test");
401 config.addConfiguration(setUpTestConfiguration());
402
403 config.clear();
404 assertEquals("Still configs contained", 0, config
405 .getNumberOfConfigurations());
406 assertTrue("Still names contained", config.getConfigurationNames()
407 .isEmpty());
408 assertTrue("Config is not empty", config.isEmpty());
409
410 listener.checkEvent(3, 2);
411 }
412
413 /***
414 * Tests if file-based configurations can be reloaded.
415 */
416 public void testReloading() throws Exception
417 {
418 config.setForceReloadCheck(true);
419 File testDir = new File("target");
420 File testXmlFile = new File(testDir, "reload.xml");
421 File testPropsFile = new File(testDir, "reload.properties");
422 writeFile(testXmlFile, "<xml><xmlReload>0</xmlReload></xml>");
423 writeFile(testPropsFile, "propsReload = 0");
424 XMLConfiguration c1 = new XMLConfiguration(testXmlFile);
425 c1.setReloadingStrategy(new FileAlwaysReloadingStrategy());
426 PropertiesConfiguration c2 = new PropertiesConfiguration(testPropsFile);
427 c2.setThrowExceptionOnMissing(true);
428 c2.setReloadingStrategy(new FileAlwaysReloadingStrategy());
429 config.addConfiguration(c1);
430 config.addConfiguration(c2);
431 assertEquals("Wrong xml reload value", 0, config.getInt("xmlReload"));
432 assertEquals("Wrong props reload value", 0, config
433 .getInt("propsReload"));
434
435 writeFile(testXmlFile, "<xml><xmlReload>1</xmlReload></xml>");
436 assertEquals("XML reload not detected", 1, config.getInt("xmlReload"));
437 config.setForceReloadCheck(false);
438 writeFile(testPropsFile, "propsReload = 1");
439 assertEquals("Props reload detected though check flag is false", 0, config
440 .getInt("propsReload"));
441
442 assertTrue("XML file cannot be removed", testXmlFile.delete());
443 assertTrue("Props file cannot be removed", testPropsFile.delete());
444 }
445
446 /***
447 * Helper method for writing a file.
448 *
449 * @param file the file to be written
450 * @param content the file's content
451 * @throws IOException if an error occurs
452 */
453 private static void writeFile(File file, String content) throws IOException
454 {
455 PrintWriter out = null;
456 try
457 {
458 out = new PrintWriter(new FileWriter(file));
459 out.print(content);
460 }
461 finally
462 {
463 if (out != null)
464 {
465 out.close();
466 }
467 }
468 }
469
470 /***
471 * Helper method for creating a test configuration to be added to the
472 * combined configuration.
473 *
474 * @return the test configuration
475 */
476 private AbstractConfiguration setUpTestConfiguration()
477 {
478 HierarchicalConfiguration config = new HierarchicalConfiguration();
479 config.addProperty(TEST_KEY, Boolean.TRUE);
480 config.addProperty("test.comment", "This is a test");
481 return config;
482 }
483
484 /***
485 * Test event listener class for checking if the expected invalidate events
486 * are fired.
487 */
488 static class CombinedListener implements ConfigurationListener
489 {
490 int invalidateEvents;
491
492 int otherEvents;
493
494 public void configurationChanged(ConfigurationEvent event)
495 {
496 if (event.getType() == CombinedConfiguration.EVENT_COMBINED_INVALIDATE)
497 {
498 invalidateEvents++;
499 }
500 else
501 {
502 otherEvents++;
503 }
504 }
505
506 /***
507 * Checks if the expected number of events was fired.
508 *
509 * @param expectedInvalidate the expected number of invalidate events
510 * @param expectedOthers the expected number of other events
511 */
512 public void checkEvent(int expectedInvalidate, int expectedOthers)
513 {
514 Assert.assertEquals("Wrong number of invalidate events",
515 expectedInvalidate, invalidateEvents);
516 Assert.assertEquals("Wrong number of other events", expectedOthers,
517 otherEvents);
518 }
519 }
520 }