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 }