Author: oheger Date: Tue Apr 2 19:08:45 2013 New Revision: 1463692 URL: http://svn.apache.org/r1463692 Log: Reworked test cases for reloading of combined configurations.
Because reloading is now handled by builders, tests related to reloading of combined configurations have been removed from TestCombinedConfiguration. A new test class has been added with corresponding tests for ReloadingCombinedConfigurationBuilder. Added: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestReloadingCombinedConfigurationBuilderFileBased.java Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/ReloadingCombinedConfigurationBuilder.java commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/ReloadingCombinedConfigurationBuilder.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/ReloadingCombinedConfigurationBuilder.java?rev=1463692&r1=1463691&r2=1463692&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/ReloadingCombinedConfigurationBuilder.java (original) +++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/ReloadingCombinedConfigurationBuilder.java Tue Apr 2 19:08:45 2013 @@ -160,7 +160,10 @@ public class ReloadingCombinedConfigurat obtainReloadingController(subControllers, b); } - return new CombinedReloadingController(subControllers); + CombinedReloadingController ctrl = + new CombinedReloadingController(subControllers); + ctrl.resetInitialReloadingState(); + return ctrl; } /** Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java?rev=1463692&r1=1463691&r2=1463692&view=diff ============================================================================== --- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java (original) +++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java Tue Apr 2 19:08:45 2013 @@ -30,7 +30,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; -import java.text.MessageFormat; import java.util.Collection; import java.util.List; import java.util.Set; @@ -39,14 +38,10 @@ import junit.framework.Assert; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; -import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; -import org.apache.commons.configuration.reloading.FileRandomReloadingStrategy; import org.apache.commons.configuration.tree.DefaultExpressionEngine; -import org.apache.commons.configuration.tree.MergeCombiner; import org.apache.commons.configuration.tree.NodeCombiner; import org.apache.commons.configuration.tree.OverrideCombiner; import org.apache.commons.configuration.tree.UnionCombiner; -import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -71,12 +66,6 @@ public class TestCombinedConfiguration /** Constant for the name of the second child configuration.*/ private static final String CHILD2 = TEST_NAME + "2"; - /** Constant for the name of the XML reload test file.*/ - private static final String RELOAD_XML_NAME = "reload.xml"; - - /** Constant for the content of a XML reload test file.*/ - private static final String RELOAD_XML_CONTENT = "<xml><xmlReload>{0}</xmlReload></xml>"; - /** Helper object for managing temporary files. */ @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -445,26 +434,6 @@ public class TestCombinedConfiguration } /** - * Tests whether the reload check works with a subnode configuration. This - * test is related to CONFIGURATION-341. - */ - @Test - public void testReloadingSubnodeConfig() throws IOException, - ConfigurationException - { - config.setForceReloadCheck(true); - File testXmlFile = writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, - 0); - XMLConfiguration c1 = new XMLConfiguration(testXmlFile); - c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); - final String prefix = "reloadCheck"; - config.addConfiguration(c1, CHILD1, prefix); - SubnodeConfiguration sub = config.configurationAt(prefix, true); - writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 1); - assertEquals("Reload not detected", 1, sub.getInt("xmlReload")); - } - - /** * Prepares a test of the getSource() method. */ private void setUpSourceTest() @@ -645,68 +614,6 @@ public class TestCombinedConfiguration } /** - * Tests whether changes on a sub node configuration that is part of a - * combined configuration are detected. This test is related to - * CONFIGURATION-368. - */ - @Test - public void testReloadWithSubNodeConfig() throws Exception - { - final String reloadContent = "<config><default><xmlReload1>{0}</xmlReload1></default></config>"; - config.setForceReloadCheck(true); - config.setNodeCombiner(new OverrideCombiner()); - File testXmlFile1 = writeReloadFile(RELOAD_XML_NAME, reloadContent, 0); - final String prefix1 = "default"; - XMLConfiguration c1 = new XMLConfiguration(testXmlFile1); - SubnodeConfiguration sub1 = c1.configurationAt(prefix1, true); - assertEquals("Inital test for sub config 1 failed", 0, sub1 - .getInt("xmlReload1")); - config.addConfiguration(sub1); - assertEquals( - "Could not get value for sub config 1 from combined config", 0, - config.getInt("xmlReload1")); - c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); - writeReloadFile(RELOAD_XML_NAME, reloadContent, 1); - assertEquals("Reload of sub config 1 not detected", 1, config - .getInt("xmlReload1")); - } - - @Test - public void testConcurrentGetAndReload() throws Exception - { - final int threadCount = 5; - final int loopCount = 1000; - config.setForceReloadCheck(true); - config.setNodeCombiner(new MergeCombiner()); - final XMLConfiguration xml = new XMLConfiguration("configA.xml"); - xml.setReloadingStrategy(new FileRandomReloadingStrategy()); - config.addConfiguration(xml); - final XMLConfiguration xml2 = new XMLConfiguration("configB.xml"); - xml2.setReloadingStrategy(new FileRandomReloadingStrategy()); - config.addConfiguration(xml2); - config.setExpressionEngine(new XPathExpressionEngine()); - - assertEquals(config.getString("/property[@name='config']/@value"), "100"); - - Thread testThreads[] = new Thread[threadCount]; - int failures[] = new int[threadCount]; - - for (int i = 0; i < testThreads.length; ++i) - { - testThreads[i] = new ReloadThread(config, failures, i, loopCount); - testThreads[i].start(); - } - - int totalFailures = 0; - for (int i = 0; i < testThreads.length; ++i) - { - testThreads[i].join(); - totalFailures += failures[i]; - } - assertTrue(totalFailures + " failures Occurred", totalFailures == 0); - } - - /** * Tests whether a combined configuration can be copied to an XML * configuration. This test is related to CONFIGURATION-445. */ @@ -739,101 +646,6 @@ public class TestCombinedConfiguration x3.getString("key2[@override]")); } - private class ReloadThread extends Thread - { - CombinedConfiguration combined; - int[] failures; - int index; - int count; - - ReloadThread(CombinedConfiguration config, int[] failures, int index, int count) - { - combined = config; - this.failures = failures; - this.index = index; - this.count = count; - } - @Override - public void run() - { - failures[index] = 0; - for (int i = 0; i < count; i++) - { - try - { - String value = combined.getString("/property[@name='config']/@value"); - if (value == null || !value.equals("100")) - { - ++failures[index]; - } - } - catch (Exception ex) - { - ++failures[index]; - } - } - } - } - - /** - * Helper method for writing a file. The file is also added to a list and - * will be deleted in teadDown() automatically. - * - * @param file the file to be written - * @param content the file's content - * @throws IOException if an error occurs - */ - private void writeFile(File file, String content) throws IOException - { - PrintWriter out = null; - try - { - out = new PrintWriter(new FileWriter(file)); - out.print(content); - } - finally - { - if (out != null) - { - out.close(); - } - } - } - - /** - * Helper method for writing a test file. The file will be created in the - * test directory. It is also scheduled for automatic deletion after the - * test. - * - * @param fileName the name of the test file - * @param content the content of the file - * @return the <code>File</code> object for the test file - * @throws IOException if an error occurs - */ - private File writeFile(String fileName, String content) throws IOException - { - File file = new File(folder.getRoot(), fileName); - writeFile(file, content); - return file; - } - - /** - * Writes a file for testing reload operations. - * - * @param name the name of the reload test file - * @param content the content of the file - * @param value the value of the reload test property - * @return the file that was written - * @throws IOException if an error occurs - */ - private File writeReloadFile(String name, String content, int value) - throws IOException - { - return writeFile(name, MessageFormat.format(content, new Object[] { - new Integer(value) - })); - } - /** * Helper method for creating a test configuration to be added to the * combined configuration. Added: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestReloadingCombinedConfigurationBuilderFileBased.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestReloadingCombinedConfigurationBuilderFileBased.java?rev=1463692&view=auto ============================================================================== --- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestReloadingCombinedConfigurationBuilderFileBased.java (added) +++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestReloadingCombinedConfigurationBuilderFileBased.java Tue Apr 2 19:08:45 2013 @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.configuration.builder.combined; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.MessageFormat; + +import org.apache.commons.configuration.BaseHierarchicalConfiguration; +import org.apache.commons.configuration.CombinedConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.HierarchicalConfiguration; +import org.apache.commons.configuration.builder.BasicConfigurationBuilder; +import org.apache.commons.configuration.builder.FileBasedBuilderParametersImpl; +import org.apache.commons.configuration.builder.ReloadingDetectorFactory; +import org.apache.commons.configuration.builder.fluent.Parameters; +import org.apache.commons.configuration.io.FileHandler; +import org.apache.commons.configuration.reloading.AlwaysReloadingDetector; +import org.apache.commons.configuration.reloading.RandomReloadingDetector; +import org.apache.commons.configuration.reloading.ReloadingDetector; +import org.apache.commons.configuration.tree.MergeCombiner; +import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** + * Test class for {@code ReloadingCombinedConfigurationBuilder} which actually + * accesses files to be reloaded. + * + * @version $Id: $ + */ +public class TestReloadingCombinedConfigurationBuilderFileBased +{ + /** Constant for the prefix for XML configuration sources. */ + private static final String PROP_SRC = "override.xml"; + + /** Constant for the prefix of the reload property. */ + private static final String PROP_RELOAD = "default.xmlReload"; + + /** Constant for content of a XML configuration for reload tests. */ + private static final String RELOAD_CONTENT = + "<config><default><xmlReload{1}>{0}</xmlReload{1}></default></config>"; + + /** A helper object for managing temporary files. */ + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + /** The builder to be tested. */ + private ReloadingCombinedConfigurationBuilder builder; + + @Before + public void setUp() throws Exception + { + builder = new ReloadingCombinedConfigurationBuilder(); + } + + /** + * Adds a source for a configuration which can be reloaded to the definition + * configuration. + * + * @param config the definition configuration + * @param fileName the name of the file + */ + private static void addReloadSource(Configuration config, String fileName) + { + config.addProperty(PROP_SRC + "(-1)[@fileName]", fileName); + config.addProperty(PROP_SRC + "[@config-reload]", Boolean.TRUE); + } + + /** + * Helper method for writing a file. + * + * @param file the file to be written + * @param content the file's content + * @throws IOException if an error occurs + */ + private static void writeFile(File file, String content) throws IOException + { + PrintWriter out = null; + try + { + out = new PrintWriter(new FileWriter(file)); + out.print(content); + } + finally + { + if (out != null) + { + out.close(); + } + } + } + + /** + * Helper method for writing a test file for reloading. The file will be + * created in the test directory. It is also scheduled for automatic + * deletion after the test. + * + * @param f the file to be written or <b>null</b> for creating a new one + * @param content the content of the file + * @return the <code>File</code> object for the test file + * @throws IOException if an error occurs + */ + private File writeReloadFile(File f, String content) throws IOException + { + File file = (f != null) ? f : folder.newFile(); + writeFile(file, content); + return file; + } + + /** + * Writes a file for testing reload operations. + * + * @param f the file to be written or <b>null</b> for creating a new one + * @param tagIdx the index of the tag + * @param value the value of the reload test property + * @return the file that was written + * @throws IOException if an error occurs + */ + private File writeReloadFile(File f, int tagIdx, int value) + throws IOException + { + return writeReloadFile(f, + MessageFormat.format(RELOAD_CONTENT, new Object[] { + value, tagIdx + })); + } + + /** + * Returns the name of a test property. + * + * @param idx the index of the property + * @return the test property with this index + */ + private static String testProperty(int idx) + { + return PROP_RELOAD + idx; + } + + /** + * Tests whether a changed file is detected on disk. + */ + @Test + public void testReloadFromFile() throws ConfigurationException, IOException + { + File xmlConf1 = writeReloadFile(null, 1, 0); + File xmlConf2 = writeReloadFile(null, 2, 0); + ReloadingDetectorFactory detectorFactory = + new ReloadingDetectorFactory() + { + public ReloadingDetector createReloadingDetector( + FileHandler handler, + FileBasedBuilderParametersImpl params) + throws ConfigurationException + { + return new AlwaysReloadingDetector(); + } + }; + HierarchicalConfiguration defConf = new BaseHierarchicalConfiguration(); + addReloadSource(defConf, xmlConf1.getAbsolutePath()); + addReloadSource(defConf, xmlConf2.getAbsolutePath()); + builder.configure(Parameters + .combined() + .setDefinitionBuilder(new ConstantConfigurationBuilder(defConf)) + .addChildParameters( + new FileBasedBuilderParametersImpl() + .setReloadingDetectorFactory(detectorFactory))); + CombinedConfiguration config = builder.getConfiguration(); + assertEquals("Wrong initial value (1)", 0, + config.getInt(testProperty(1))); + assertEquals("Wrong initial value (2)", 0, + config.getInt(testProperty(2))); + + writeReloadFile(xmlConf1, 1, 1); + builder.getReloadingController().checkForReloading(null); + config = builder.getConfiguration(); + assertEquals("Updated value not reloaded (1)", 1, + config.getInt(testProperty(1))); + assertEquals("Value modified", 0, config.getInt(testProperty(2))); + + writeReloadFile(xmlConf2, 2, 2); + builder.getReloadingController().checkForReloading(null); + config = builder.getConfiguration(); + assertEquals("Wrong value for config 1", 1, + config.getInt(testProperty(1))); + assertEquals("Updated value not reloaded (2)", 2, + config.getInt(testProperty(2))); + } + + /** + * Tests concurrent access to a reloading builder for combined + * configurations. + */ + @Test + public void testConcurrentGetAndReload() throws Exception + { + final int threadCount = 4; + final int loopCount = 100; + ReloadingDetectorFactory detectorFactory = + new ReloadingDetectorFactory() + { + public ReloadingDetector createReloadingDetector( + FileHandler handler, + FileBasedBuilderParametersImpl params) + throws ConfigurationException + { + return new RandomReloadingDetector(); + } + }; + HierarchicalConfiguration defConf = new BaseHierarchicalConfiguration(); + defConf.addProperty("header.result.nodeCombiner[@config-class]", + MergeCombiner.class.getName()); + defConf.addProperty("header.result.expressionEngine[@config-class]", + XPathExpressionEngine.class.getName()); + addReloadSource(defConf, "configA.xml"); + addReloadSource(defConf, "configB.xml"); + builder.configure(Parameters + .combined() + .setDefinitionBuilder(new ConstantConfigurationBuilder(defConf)) + .addChildParameters( + new FileBasedBuilderParametersImpl() + .setReloadingDetectorFactory(detectorFactory))); + + assertEquals("Wrong initial value", "100", builder.getConfiguration() + .getString("/property[@name='config']/@value")); + + Thread testThreads[] = new Thread[threadCount]; + int failures[] = new int[threadCount]; + + for (int i = 0; i < testThreads.length; ++i) + { + testThreads[i] = new ReloadThread(builder, failures, i, loopCount); + testThreads[i].start(); + } + + int totalFailures = 0; + for (int i = 0; i < testThreads.length; ++i) + { + testThreads[i].join(); + totalFailures += failures[i]; + } + assertTrue(totalFailures + " failures Occurred", totalFailures == 0); + } + + /** + * A test builder class which always returns the same configuration. + */ + private static class ConstantConfigurationBuilder extends + BasicConfigurationBuilder<HierarchicalConfiguration> + { + private final HierarchicalConfiguration configuration; + + public ConstantConfigurationBuilder(HierarchicalConfiguration conf) + { + super(HierarchicalConfiguration.class); + configuration = conf; + } + + @Override + public HierarchicalConfiguration getConfiguration() + throws ConfigurationException + { + return configuration; + } + } + + /** + * A thread class for testing concurrent reload operations. + */ + private static class ReloadThread extends Thread + { + /** The builder to be queried. */ + private final ReloadingCombinedConfigurationBuilder builder; + + /** An array for reporting failures. */ + private final int[] failures; + + /** The index of this thread in the array with failures. */ + private final int index; + + /** The number of test operations. */ + private final int count; + + ReloadThread(ReloadingCombinedConfigurationBuilder bldr, + int[] failures, int index, int count) + { + builder = bldr; + this.failures = failures; + this.index = index; + this.count = count; + } + + @Override + public void run() + { + failures[index] = 0; + for (int i = 0; i < count; i++) + { + try + { + builder.getReloadingController().checkForReloading(null); + String value = + builder.getConfiguration().getString( + "/property[@name='config']/@value"); + if (value == null || !value.equals("100")) + { + ++failures[index]; + } + } + catch (Exception ex) + { + ++failures[index]; + } + } + } + } +}