View Javadoc

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