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