    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 java.io.File;
    21  import java.io.FileInputStream;
    22  import java.io.FileOutputStream;
    23  import java.io.FileWriter;
    24  import java.io.IOException;
    25  import java.io.PrintWriter;
    26  import java.net.URL;
    27  import java.util.Iterator;
    28  import java.util.Properties;
    29
    30  import junit.framework.TestCase;
    31
    32  import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
    33  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
    34
    35  /***
    36   * @author Emmanuel Bourg
    37   * @version $Revision: 711782 $, $Date: 2008-11-06 08:23:41 +0100 (Do, 06 Nov 2008) $
    38   */
    39  public class TestFileConfiguration extends TestCase
    40  {
    41      /*** Constant for the output directory.*/
    42      private static final File TARGET_DIR = new File("target");
    43
    44      /*** Constant for the directory with the test configuration files.*/
    45      private static final File TEST_DIR = new File("conf");
    46
    47      /*** Constant for the name of a test file.*/
    48      private static final String TEST_FILENAME = "test.properties";
    49
    50      /*** Constant for a test file.*/
    51      private static final File TEST_FILE = new File(TEST_DIR, TEST_FILENAME);
    52
    53      /*** Constant for the name of a resource to be resolved.*/
    54      private static final String RESOURCE_NAME = "config/deep/deeptest.properties";
    55
    56      public void testSetURL() throws Exception
    57      {
    58          // http URL
    59          FileConfiguration config = new PropertiesConfiguration();
    60          config.setURL(new URL("http://commons.apache.org/configuration/index.html"));
    61
    62          assertEquals("base path", "http://commons.apache.org/configuration/", config.getBasePath());
    63          assertEquals("file name", "index.html", config.getFileName());
    64
    65          // file URL
    66          config.setURL(new URL("file:/temp/test.properties"));
    67          assertEquals("base path", "file:/temp/", config.getBasePath());
    68          assertEquals("file name", "test.properties", config.getFileName());
    69      }
    70
    71      public void testSetURLWithParams() throws Exception
    72      {
    73          FileConfiguration config = new PropertiesConfiguration();
    74          URL url = new URL("http://issues.apache.org/bugzilla/show_bug.cgi?id=37886");
    75          config.setURL(url);
    76          assertEquals("Base path incorrect", "http://issues.apache.org/bugzilla/", config.getBasePath());
    77          assertEquals("File name incorrect", "show_bug.cgi", config.getFileName());
    78          assertEquals("URL was not correctly stored", url, config.getURL());
    79      }
    80
    81      public void testLocations() throws Exception
    82      {
    83          PropertiesConfiguration config = new PropertiesConfiguration();
    84
    85          File directory = TEST_DIR;
    86          File file = TEST_FILE;
    87          config.setFile(file);
    88          assertEquals(directory.getAbsolutePath(), config.getBasePath());
    89          assertEquals(TEST_FILENAME, config.getFileName());
    90          assertEquals(file.getAbsolutePath(), config.getPath());
    91
    92          config.setPath("conf" + File.separator + TEST_FILENAME);
    93          assertEquals(TEST_FILENAME, config.getFileName());
    94          assertEquals(directory.getAbsolutePath(), config.getBasePath());
    95          assertEquals(file.getAbsolutePath(), config.getPath());
    96          assertEquals(file.toURL(), config.getURL());
    97
    98          config.setBasePath(null);
    99          config.setFileName(TEST_FILENAME);
    100         assertNull(config.getBasePath());
    101         assertEquals(TEST_FILENAME, config.getFileName());
    102     }
    103
    104     public void testCreateFile1() throws Exception
    105     {
    106         File file = new File("target/test-resources/foo/bar/test.properties");
    107         if (file.exists())
    108         {
    109             file.delete();
    110             file.getParentFile().delete();
    111         }
    112
    113         assertFalse("The file should not exist", file.exists());
    114
    115         FileConfiguration config = new PropertiesConfiguration(file);
    116         config.save();
    117
    118         assertTrue("The file doesn't exist", file.exists());
    119     }
    120
    121     public void testCreateFile2() throws Exception
    122     {
    123         File file = new File("target/test-resources/foo/bar/test.properties");
    124         if (file.exists())
    125         {
    126             file.delete();
    127             file.getParentFile().delete();
    128         }
    129
    130         assertFalse("The file should not exist", file.exists());
    131
    132         FileConfiguration config = new PropertiesConfiguration();
    133         config.setFile(file);
    134         config.save();
    135
    136         assertTrue("The file doesn't exist", file.exists());
    137     }
    138
    139     public void testCreateFile3() throws Exception
    140     {
    141         File file = new File("target/test-resources/foo/bar/test.properties");
    142         if (file.exists())
    143         {
    144             file.delete();
    145             file.getParentFile().delete();
    146         }
    147
    148         assertFalse("The file should not exist", file.exists());
    149
    150         FileConfiguration config = new PropertiesConfiguration();
    151         config.save(file);
    152
    153         assertTrue("The file doesn't exist", file.exists());
    154     }
    155
    156     /***
    157      * Tests collaboration with ConfigurationFactory: Is the base path set on
    158      * loading is valid in file based configurations?
    159      *
    160      * @throws Exception if an error occurs
    161      */
    162     public void testWithConfigurationFactory() throws Exception
    163     {
    164         File dir = new File("conf");
    165         File file = new File(dir, "testFileConfiguration.properties");
    166
    167         if (file.exists())
    168         {
    169             assertTrue("File cannot be deleted", file.delete());
    170         }
    171
    172         try
    173         {
    174             ConfigurationFactory factory = new ConfigurationFactory();
    175             factory.setConfigurationURL(new File(dir, "testDigesterConfiguration2.xml").toURL());
    176             CompositeConfiguration cc = (CompositeConfiguration) factory.getConfiguration();
    177             PropertiesConfiguration config = null;
    178             for (int i = 0; config == null; i++)
    179             {
    180                 if (cc.getConfiguration(i) instanceof PropertiesConfiguration)
    181                 {
    182                     config = (PropertiesConfiguration) cc.getConfiguration(i);
    183                 }
    184             }
    185
    186             config.setProperty("test", "yes");
    187             config.save(file.getName());
    188             assertTrue(file.exists());
    189             config = new PropertiesConfiguration();
    190             config.setFile(file);
    191             config.load();
    192
    193             assertEquals("yes", config.getProperty("test"));
    194             assertEquals("masterOfPost", config.getProperty("mail.account.user"));
    195         }
    196         finally
    197         {
    198             if (file.exists())
    199             {
    200                 assertTrue("File could not be deleted", file.delete());
    201             }
    202         }
    203     }
    204
    205     /***
    206      * Tests if invalid URLs cause an exception.
    207      */
    208     public void testSaveInvalidURL() throws Exception
    209     {
    210         FileConfiguration config = new PropertiesConfiguration();
    211
    212         try
    213         {
    214             config.save(new URL("http://jakarta.apache.org/test.properties"));
    215             fail("Should throw a ConfigurationException!");
    216         }
    217         catch (ConfigurationException cex)
    218         {
    219             //fine
    220         }
    221
    222         try
    223         {
    224             config.save("http://www.apache.org/test.properties");
    225             fail("Should throw a ConfigurationException!");
    226         }
    227         catch (ConfigurationException cex)
    228         {
    229             //fine
    230         }
    231     }
    232
    233     /***
    234      * Tests if the URL used by the load() method is also used by save().
    235      */
    236     public void testFileOverwrite() throws Exception
    237     {
    238         FileOutputStream out = null;
    239         FileInputStream in = null;
    240         File tempFile = null;
    241         try
    242         {
    243             String path = System.getProperties().getProperty("user.home");
    244             File homeDir = new File(path);
    245             tempFile = File.createTempFile("CONF", null, homeDir);
    246             String fileName = tempFile.getName();
    247             Properties props = new Properties();
    248             props.setProperty("1", "one");
    249             out = new FileOutputStream(tempFile);
    250             props.store(out, "TestFileOverwrite");
    251             out.close();
    252             out = null;
    253             FileConfiguration config = new PropertiesConfiguration(fileName);
    254             config.load();
    255             String value = config.getString("1");
    256             assertTrue("one".equals(value));
    257             config.setProperty("1", "two");
    258             config.save();
    259             props = new Properties();
    260             in = new FileInputStream(tempFile);
    261             props.load(in);
    262             String value2 = props.getProperty("1");
    263             assertTrue("two".equals(value2));
    264         }
    265         finally
    266         {
    267             if (out != null)
    268             {
    269                 try
    270                 {
    271                     out.close();
    272                 }
    273                 catch (IOException ioex)
    274                 {
    275                     ioex.printStackTrace();
    276                 }
    277             }
    278             if (in != null)
    279             {
    280                 try
    281                 {
    282                     in.close();
    283                 }
    284                 catch (IOException ioex)
    285                 {
    286                     ioex.printStackTrace();
    287                 }
    288             }
    289             if (tempFile.exists())
    290             {
    291                 assertTrue(tempFile.delete());
    292             }
    293         }
    294     }
    295
    296     /***
    297      * Tests setting a file changed reloading strategy together with the auto
    298      * save feature.
    299      */
    300     public void testReloadingWithAutoSave() throws Exception
    301     {
    302         File configFile = new File(TARGET_DIR, TEST_FILENAME);
    303         PrintWriter out = null;
    304
    305         try
    306         {
    307             out = new PrintWriter(new FileWriter(configFile));
    308             out.println("a = one");
    309             out.close();
    310             out = null;
    311
    312             PropertiesConfiguration config = new PropertiesConfiguration(
    313                     configFile);
    314             config.setReloadingStrategy(new FileChangedReloadingStrategy());
    315             config.setAutoSave(true);
    316
    317             assertEquals("one", config.getProperty("a"));
    318             config.setProperty("b", "two");
    319             assertEquals("one", config.getProperty("a"));
    320         }
    321         finally
    322         {
    323             if (out != null)
    324             {
    325                 out.close();
    326             }
    327             if (configFile.exists())
    328             {
    329                 assertTrue(configFile.delete());
    330             }
    331         }
    332     }
    333
    334     /***
    335      * Tests loading and saving a configuration file with a complicated path
    336      * name including spaces. (related to issue 35210)
    337      */
    338     public void testPathWithSpaces() throws Exception
    339     {
    340         File path = new File(TARGET_DIR, "path with spaces");
    341         File confFile = new File(path, "config-test.properties");
    342         PrintWriter out = null;
    343
    344         try
    345         {
    346             if (!path.exists())
    347             {
    348                 assertTrue(path.mkdir());
    349             }
    350             out = new PrintWriter(new FileWriter(confFile));
    351             out.println("saved = false");
    352             out.close();
    353             out = null;
    354
    355             URL url = new URL(TARGET_DIR.toURL()
    356                     + "path%20with%20spaces/config-test.properties");
    357             PropertiesConfiguration config = new PropertiesConfiguration(url);
    358             config.load();
    359             assertFalse(config.getBoolean("saved"));
    360
    361             config.setProperty("saved", Boolean.TRUE);
    362             config.save();
    363             config = new PropertiesConfiguration();
    364             config.setFile(confFile);
    365             config.load();
    366             assertTrue(config.getBoolean("saved"));
    367         }
    368         finally
    369         {
    370             if (out != null)
    371             {
    372                 out.close();
    373             }
    374             if (confFile.exists())
    375             {
    376                 assertTrue(confFile.delete());
    377             }
    378             if (path.exists())
    379             {
    380                 assertTrue(path.delete());
    381             }
    382         }
    383     }
    384
    385     /***
    386      * Tests the getFile() method.
    387      */
    388     public void testGetFile() throws ConfigurationException
    389     {
    390         FileConfiguration config = new PropertiesConfiguration();
    391         assertNull(config.getFile());
    392         File file = TEST_FILE.getAbsoluteFile();
    393         config.setFile(file);
    394         assertEquals(file, config.getFile());
    395         config.load();
    396         assertEquals(file, config.getFile());
    397     }
    398
    399     /***
    400      * Tests whether getFile() returns a valid file after a configuration has
    401      * been loaded.
    402      */
    403     public void testGetFileAfterLoad() throws ConfigurationException,
    404             IOException
    405     {
    406         FileConfiguration config = new PropertiesConfiguration();
    407         config.load(TEST_FILE.getAbsolutePath());
    408         assertNotNull("No source URL set", config.getURL());
    409         assertEquals("Wrong source file", TEST_FILE.getCanonicalFile(), config
    410                 .getFile().getCanonicalFile());
    411     }
    412
    413     /***
    414      * Tests whether calling load() multiple times changes the source. This
    415      * should not be the case.
    416      */
    417     public void testLoadMultiple() throws ConfigurationException
    418     {
    419         FileConfiguration config = new PropertiesConfiguration();
    420         config.load(TEST_FILE.getAbsolutePath());
    421         URL srcUrl = config.getURL();
    422         File srcFile = config.getFile();
    423         File file2 = new File(TEST_DIR, "testEqual.properties");
    424         config.load(file2.getAbsolutePath());
    425         assertEquals("Source URL was changed", srcUrl, config.getURL());
    426         assertEquals("Source file was changed", srcFile, config.getFile());
    427     }
    428
    429     /***
    430      * Tests to invoke save() without explicitly setting a file name. This
    431      * will cause an exception.
    432      */
    433     public void testSaveWithoutFileName() throws Exception
    434     {
    435         FileConfiguration config = new PropertiesConfiguration();
    436         File file = TEST_FILE;
    437         config.load(file);
    438         try
    439         {
    440             config.save();
    441             fail("Could save config without setting a file name!");
    442         }
    443         catch(ConfigurationException cex)
    444         {
    445             //ok
    446         }
    447
    448         config = new PropertiesConfiguration();
    449         config.load(TEST_FILE);
    450         try
    451         {
    452             config.save();
    453             fail("Could save config without setting a file name!");
    454         }
    455         catch(ConfigurationException cex)
    456         {
    457             //ok
    458         }
    459
    460         config = new PropertiesConfiguration();
    461         config.load(file.toURL());
    462         try
    463         {
    464             config.save();
    465             fail("Could save config without setting a file name!");
    466         }
    467         catch(ConfigurationException cex)
    468         {
    469             //ok
    470         }
    471     }
    472
    473     /***
    474      * Checks that loading a directory instead of a file throws an exception.
    475      */
    476     public void testLoadDirectory()
    477     {
    478         PropertiesConfiguration config = new PropertiesConfiguration();
    479
    480         try
    481         {
    482             config.load("target");
    483             fail("Could load config from a directory!");
    484         }
    485         catch (ConfigurationException e)
    486         {
    487             // ok
    488         }
    489
    490         try
    491         {
    492             config.load(new File("target"));
    493             fail("Could load config from a directory!");
    494         }
    495         catch (ConfigurationException e)
    496         {
    497             // ok
    498         }
    499
    500         try
    501         {
    502             new PropertiesConfiguration("target");
    503             fail("Could load config from a directory!");
    504         }
    505         catch (ConfigurationException e)
    506         {
    507             // ok
    508         }
    509
    510         try
    511         {
    512             new PropertiesConfiguration(new File("target"));
    513             fail("Could load config from a directory!");
    514         }
    515         catch (ConfigurationException e)
    516         {
    517             // ok
    518         }
    519     }
    520
    521     /***
    522      * Tests whether the constructor behaves the same as setFileName() when the
    523      * configuration source is in the classpath.
    524      */
    525     public void testInitFromClassPath() throws ConfigurationException
    526     {
    527         PropertiesConfiguration config1 = new PropertiesConfiguration();
    528         config1.setFileName(RESOURCE_NAME);
    529         config1.load();
    530         PropertiesConfiguration config2 = new PropertiesConfiguration(
    531                 RESOURCE_NAME);
    532         compare(config1, config2);
    533     }
    534
    535     /***
    536      * Tests the loading of configuration file in a Combined configuration
    537      * when the configuration source is in the classpath.
    538      */
    539     public void testLoadFromClassPath() throws ConfigurationException
    540     {
    541         DefaultConfigurationBuilder cf =
    542             new DefaultConfigurationBuilder("conf/config/deep/testFileFromClasspath.xml");
    543         CombinedConfiguration config = cf.getConfiguration(true);
    544         Configuration config1 = config.getConfiguration("propConf");
    545         Configuration config2 = config.getConfiguration("propConfDeep");
    546         compare(config1, config2);
    547     }
    548
    549     /***
    550      * Tests cloning a file based configuration.
    551      */
    552     public void testClone() throws ConfigurationException
    553     {
    554         PropertiesConfiguration config = new PropertiesConfiguration(
    555                 RESOURCE_NAME);
    556         PropertiesConfiguration copy = (PropertiesConfiguration) config.clone();
    557         compare(config, copy);
    558         assertNull("URL was not reset", copy.getURL());
    559         assertNull("Base path was not reset", copy.getBasePath());
    560         assertNull("File name was not reset", copy.getFileName());
    561         assertNotSame("Reloading strategy was not reset", config
    562                 .getReloadingStrategy(), copy.getReloadingStrategy());
    563     }
    564
    565     /***
    566      * Tests whether an error log listener was registered at the configuration.
    567      */
    568     public void testLogErrorListener()
    569     {
    570         PropertiesConfiguration config = new PropertiesConfiguration();
    571         assertEquals("No error log listener registered", 1, config
    572                 .getErrorListeners().size());
    573     }
    574
    575     /***
    576      * Tests handling of errors in the reload() method.
    577      */
    578     public void testReloadError() throws ConfigurationException
    579     {
    580         ConfigurationErrorListenerImpl l = new ConfigurationErrorListenerImpl();
    581         PropertiesConfiguration config = new PropertiesConfiguration(
    582                 RESOURCE_NAME);
    583         config.clearErrorListeners();
    584         config.addErrorListener(l);
    585         config.setReloadingStrategy(new FileAlwaysReloadingStrategy());
    586         config.getString("test");
    587         config.setFileName("Not existing file");
    588         config.getString("test");
    589         l.verify(AbstractFileConfiguration.EVENT_RELOAD, null, null);
    590         assertNotNull("Exception is not set", l.getLastEvent().getCause());
    591     }
    592
    593     /***
    594      * Tests iterating over the keys of a non hierarchical file-based
    595      * configuration while a reload happens. This test is related to
    596      * CONFIGURATION-347.
    597      */
    598     public void testIterationWithReloadFlat() throws ConfigurationException
    599     {
    600         PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE);
    601         checkIterationWithReload(config);
    602     }
    603
    604     /***
    605      * Tests iterating over the keys of a hierarchical file-based configuration
    606      * while a reload happens. This test is related to CONFIGURATION-347.
    607      */
    608     public void testIterationWithReloadHierarchical()
    609             throws ConfigurationException
    610     {
    611         XMLConfiguration config = new XMLConfiguration("test.xml");
    612         checkIterationWithReload(config);
    613     }
    614
    615     /***
    616      * Helper method for testing an iteration over the keys of a file-based
    617      * configuration while a reload happens.
    618      *
    619      * @param config the configuration to test
    620      */
    621     private void checkIterationWithReload(FileConfiguration config)
    622     {
    623         config.setReloadingStrategy(new FileAlwaysReloadingStrategy());
    624         for (Iterator it = config.getKeys(); it.hasNext();)
    625         {
    626             String key = (String) it.next();
    627             assertNotNull("No value for key " + key, config.getProperty(key));
    628         }
    629     }
    630
    631     /***
    632      * Helper method for comparing the content of two configuration objects.
    633      *
    634      * @param config1 the first configuration
    635      * @param config2 the second configuration
    636      */
    637     private void compare(Configuration config1, Configuration config2)
    638     {
    639         StrictConfigurationComparator cc = new StrictConfigurationComparator();
    640         assertTrue("Configurations are different", cc.compare(config1, config2));
    641     }
    642 }