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  package org.apache.log4j;
18  
19  import junit.framework.TestCase;
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.net.URL;
26  import java.util.Properties;
27  import java.util.zip.ZipEntry;
28  import java.util.zip.ZipOutputStream;
29  
30  import org.apache.log4j.spi.OptionHandler;
31  import org.apache.log4j.spi.Filter;
32  import org.apache.log4j.spi.LoggingEvent;
33  import org.apache.log4j.spi.ThrowableRenderer;
34  import org.apache.log4j.spi.ThrowableRendererSupport;
35  import org.apache.log4j.varia.LevelRangeFilter;
36  
37  /**
38   * Test property configurator.
39   *
40   */
41  public class PropertyConfiguratorTest extends TestCase {
42      public PropertyConfiguratorTest(final String testName) {
43          super(testName);
44      }
45  
46      /**
47       * Test for bug 40944.
48       * Did not catch IllegalArgumentException on Properties.load
49       * and close input stream.
50       * @throws IOException if IOException creating properties file.
51       */
52      public void testBadUnicodeEscape() throws IOException {
53          String fileName = "output/badescape.properties";
54          FileWriter writer = new FileWriter(fileName);
55          writer.write("log4j.rootLogger=\\uXX41");
56          writer.close();
57          PropertyConfigurator.configure(fileName);
58          File file = new File(fileName);
59          assertTrue(file.delete()) ;
60          assertFalse(file.exists());
61      }
62  
63      /**
64       * Test for bug 40944.
65       * configure(URL) never closed opened stream.
66       * @throws IOException if IOException creating properties file.
67       */
68          public void testURL() throws IOException {
69          File file = new File("output/unclosed.properties");
70          FileWriter writer = new FileWriter(file);
71          writer.write("log4j.rootLogger=debug");
72          writer.close();
73          URL url = file.toURL();
74          PropertyConfigurator.configure(url);
75          assertTrue(file.delete());
76          assertFalse(file.exists());
77      }
78  
79      /**
80       * Test for bug 40944.
81       * configure(URL) did not catch IllegalArgumentException and
82       * did not close stream.
83       * @throws IOException if IOException creating properties file.
84       */
85          public void testURLBadEscape() throws IOException {
86          File file = new File("output/urlbadescape.properties");
87          FileWriter writer = new FileWriter(file);
88          writer.write("log4j.rootLogger=\\uXX41");
89          writer.close();
90          URL url = file.toURL();
91          PropertyConfigurator.configure(url);
92          assertTrue(file.delete());
93          assertFalse(file.exists());
94      }
95  
96      /**
97       * Test for bug 47465.
98       * configure(URL) did not close opened JarURLConnection.
99       * @throws IOException if IOException creating properties jar.
100      */
101     public void testJarURL() throws IOException {
102         File dir = new File("output");
103         dir.mkdirs();
104         File file = new File("output/properties.jar");
105         ZipOutputStream zos =
106             new ZipOutputStream(new FileOutputStream(file));
107         zos.putNextEntry(new ZipEntry(LogManager.DEFAULT_CONFIGURATION_FILE));
108         zos.write("log4j.rootLogger=debug".getBytes());
109         zos.closeEntry();
110         zos.close();
111         URL url = new URL("jar:" + file.toURL() + "!/" +
112                 LogManager.DEFAULT_CONFIGURATION_FILE);
113         PropertyConfigurator.configure(url);
114         assertTrue(file.delete());
115         assertFalse(file.exists());
116     }
117 
118     /**
119      * Test processing of log4j.reset property, see bug 17531.
120      *
121      */
122     public void testReset() {
123         VectorAppender appender = new VectorAppender();
124         appender.setName("A1");
125         Logger.getRootLogger().addAppender(appender);
126         Properties props = new Properties();
127         props.put("log4j.reset", "true");
128         PropertyConfigurator.configure(props);
129         assertNull(Logger.getRootLogger().getAppender("A1"));
130         LogManager.resetConfiguration();
131     }
132 
133 
134     /**
135      * Mock definition of org.apache.log4j.rolling.RollingPolicy
136      * from extras companion.
137      */
138     public static class RollingPolicy implements OptionHandler {
139         private boolean activated = false;
140 
141         public RollingPolicy() {
142 
143         }
144         public void activateOptions() {
145             activated = true;
146         }
147 
148         public final boolean isActivated() {
149             return activated;
150         }
151 
152     }
153 
154     /**
155      * Mock definition of FixedWindowRollingPolicy from extras companion.
156      */
157     public static final class FixedWindowRollingPolicy extends RollingPolicy {
158         private String activeFileName;
159         private String fileNamePattern;
160         private int minIndex;
161 
162         public FixedWindowRollingPolicy() {
163             minIndex = -1;
164         }
165 
166         public String getActiveFileName() {
167             return activeFileName;
168         }
169         public void setActiveFileName(final String val) {
170             activeFileName = val;
171         }
172 
173         public String getFileNamePattern() {
174             return fileNamePattern;
175         }
176         public void setFileNamePattern(final String val) {
177             fileNamePattern = val;
178         }
179 
180         public int getMinIndex() {
181             return minIndex;
182         }
183 
184         public void setMinIndex(final int val) {
185             minIndex = val;
186         }
187     }
188 
189     /**
190      * Mock definition of TriggeringPolicy from extras companion.
191      */
192     public static class TriggeringPolicy implements OptionHandler {
193         private boolean activated = false;
194 
195         public TriggeringPolicy() {
196 
197         }
198         public void activateOptions() {
199             activated = true;
200         }
201 
202         public final boolean isActivated() {
203             return activated;
204         }
205 
206     }
207 
208     /**
209      * Mock definition of FilterBasedTriggeringPolicy from extras companion.
210      */
211     public static final class FilterBasedTriggeringPolicy extends TriggeringPolicy {
212         private Filter filter;
213         public FilterBasedTriggeringPolicy() {
214         }
215 
216         public void setFilter(final Filter val) {
217              filter = val;
218         }
219 
220         public Filter getFilter() {
221             return filter;
222 
223         }
224     }
225 
226     /**
227      * Mock definition of org.apache.log4j.rolling.RollingFileAppender
228      * from extras companion.
229      */
230     public static final class RollingFileAppender extends AppenderSkeleton {
231         private RollingPolicy rollingPolicy;
232         private TriggeringPolicy triggeringPolicy;
233         private boolean append;
234 
235         public RollingFileAppender() {
236 
237         }
238 
239         public RollingPolicy getRollingPolicy() {
240             return rollingPolicy;
241         }
242 
243         public void setRollingPolicy(final RollingPolicy policy) {
244             rollingPolicy = policy;
245         }
246 
247         public TriggeringPolicy getTriggeringPolicy() {
248             return triggeringPolicy;
249         }
250 
251         public void setTriggeringPolicy(final TriggeringPolicy policy) {
252             triggeringPolicy = policy;
253         }
254 
255         public boolean getAppend() {
256             return append;
257         }
258 
259         public void setAppend(boolean val) {
260             append = val;
261         }
262 
263         public void close() {
264 
265         }
266 
267         public boolean requiresLayout() {
268             return true;
269         }
270 
271         public void append(final LoggingEvent event) {
272 
273         }
274     }
275 
276     /**
277      * Test processing of nested objects, see bug 36384.
278      *
279      */
280     public void testNested() {
281         PropertyConfigurator.configure("input/filter1.properties");
282         RollingFileAppender rfa = (RollingFileAppender)
283                 Logger.getLogger("org.apache.log4j.PropertyConfiguratorTest")
284                    .getAppender("ROLLING");
285         FixedWindowRollingPolicy rollingPolicy = (FixedWindowRollingPolicy) rfa.getRollingPolicy();
286         assertEquals("filterBase-test1.log", rollingPolicy.getActiveFileName());
287         assertEquals("filterBased-test1.%i", rollingPolicy.getFileNamePattern());
288         assertEquals(0, rollingPolicy.getMinIndex());
289         assertTrue(rollingPolicy.isActivated());
290         FilterBasedTriggeringPolicy triggeringPolicy =
291                 (FilterBasedTriggeringPolicy) rfa.getTriggeringPolicy();
292         LevelRangeFilter filter = (LevelRangeFilter) triggeringPolicy.getFilter();
293         assertTrue(Level.INFO.equals(filter.getLevelMin()));
294         LogManager.resetConfiguration();
295     }
296 
297 
298     /**
299      * Mock ThrowableRenderer for testThrowableRenderer.  See bug 45721.
300      */
301     public static class MockThrowableRenderer implements ThrowableRenderer, OptionHandler {
302         private boolean activated = false;
303         private boolean showVersion = true;
304 
305         public MockThrowableRenderer() {
306         }
307 
308         public void activateOptions() {
309             activated = true;
310         }
311 
312         public boolean isActivated() {
313             return activated;
314         }
315 
316         public String[] doRender(final Throwable t) {
317             return new String[0];
318         }
319 
320         public void setShowVersion(boolean v) {
321             showVersion = v;
322         }
323 
324         public boolean getShowVersion() {
325             return showVersion;
326         }
327     }
328 
329     /**
330      * Test of log4j.throwableRenderer support.  See bug 45721.
331      */
332     public void testThrowableRenderer() {
333         Properties props = new Properties();
334         props.put("log4j.throwableRenderer", "org.apache.log4j.PropertyConfiguratorTest$MockThrowableRenderer");
335         props.put("log4j.throwableRenderer.showVersion", "false");
336         PropertyConfigurator.configure(props);
337         ThrowableRendererSupport repo = (ThrowableRendererSupport) LogManager.getLoggerRepository();
338         MockThrowableRenderer renderer = (MockThrowableRenderer) repo.getThrowableRenderer();
339         LogManager.resetConfiguration();
340         assertNotNull(renderer);
341         assertEquals(true, renderer.isActivated());
342         assertEquals(false, renderer.getShowVersion());
343     }
344 }