    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.log4j.xml;
    19
    20  import junit.framework.TestCase;
    21  import org.apache.log4j.Appender;
    22  import org.apache.log4j.FileAppender;
    23  import org.apache.log4j.Level;
    24  import org.apache.log4j.LogManager;
    25  import org.apache.log4j.Logger;
    26  import org.apache.log4j.VectorAppender;
    27  import org.apache.log4j.spi.ErrorHandler;
    28  import org.apache.log4j.spi.LoggerFactory;
    29  import org.apache.log4j.spi.LoggingEvent;
    30  import org.apache.log4j.spi.ThrowableRenderer;
    31  import org.apache.log4j.spi.OptionHandler;
    32  import org.apache.log4j.spi.ThrowableRendererSupport;
    33  import org.apache.log4j.util.Compare;
    34  import org.apache.log4j.util.ControlFilter;
    35  import org.apache.log4j.util.Filter;
    36  import org.apache.log4j.util.ISO8601Filter;
    37  import org.apache.log4j.util.JunitTestRunnerFilter;
    38  import org.apache.log4j.util.LineNumberFilter;
    39  import org.apache.log4j.util.SunReflectFilter;
    40  import org.apache.log4j.util.Transformer;
    41
    42  import java.io.File;
    43  import java.io.FileInputStream;
    44  import java.io.FileOutputStream;
    45  import java.io.IOException;
    46  import java.io.InputStream;
    47  import java.net.URL;
    48  import java.util.zip.ZipEntry;
    49  import java.util.zip.ZipOutputStream;
    50
    51  public class DOMTestCase extends TestCase {
    52
    53    static String TEMP_A1 = "output/temp.A1";
    54    static String TEMP_A2 = "output/temp.A2";
    55    static String FILTERED_A1 = "output/filtered.A1";
    56    static String FILTERED_A2 = "output/filtered.A2";
    57
    58
    59    static String EXCEPTION1 = "java.lang.Exception: Just testing";
    60    static String EXCEPTION2 = "\\s*at .*\\(.*\\)";
    61    static String EXCEPTION3 = "\\s*at .*\\(Native Method\\)";
    62    static String EXCEPTION4 = "\\s*at .*\\(.*Compiled Code\\)";
    63    static String EXCEPTION5 = "\\s*at .*\\(.*libgcj.*\\)";
    64
    65
    66    static String TEST1_1A_PAT =
    67                         "(TRACE|DEBUG|INFO |WARN |ERROR|FATAL) \\w*\\.\\w* - Message \\d";
    68
    69    static String TEST1_1B_PAT = "(TRACE|DEBUG|INFO |WARN |ERROR|FATAL) root - Message \\d";
    70
    71    static String TEST1_2_PAT = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3} "+
    72                          "\\[main]\\ (TRACE|DEBUG|INFO|WARN|ERROR|FATAL) .* - Message \\d";
    73
    74
    75
    76    Logger root;
    77    Logger logger;
    78
    79    public DOMTestCase(String name) {
    80      super(name);
    81    }
    82
    83    public void setUp() {
    84      root = Logger.getRootLogger();
    85      logger = Logger.getLogger(DOMTestCase.class);
    86    }
    87
    88    public void tearDown() {
    89      root.getLoggerRepository().resetConfiguration();
    90    }
    91
    92    public void test1() throws Exception {
    93      DOMConfigurator.configure("input/xml/DOMTestCase1.xml");
    94      common();
    95
    96      ControlFilter cf1 = new ControlFilter(new String[]{TEST1_1A_PAT, TEST1_1B_PAT,
    97  					       EXCEPTION1, EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
    98
    99      ControlFilter cf2 = new ControlFilter(new String[]{TEST1_2_PAT,
    100 					       EXCEPTION1, EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
    101
    102     Transformer.transform(
    103       TEMP_A1, FILTERED_A1,
    104       new Filter[] {
    105         cf1, new LineNumberFilter(), new SunReflectFilter(),
    106         new JunitTestRunnerFilter()
    107       });
    108
    109     Transformer.transform(
    110       TEMP_A2, FILTERED_A2,
    111       new Filter[] {
    112         cf2, new LineNumberFilter(), new ISO8601Filter(),
    113         new SunReflectFilter(), new JunitTestRunnerFilter()
    114       });
    115
    116     assertTrue(Compare.compare(FILTERED_A1, "witness/dom.A1.1"));
    117     assertTrue(Compare.compare(FILTERED_A2, "witness/dom.A2.1"));
    118   }
    119
    120   /**
    121    *   Tests processing of external entities in XML file.
    122    */
    123   public void test4() throws Exception {
    124     DOMConfigurator.configure("input/xml/DOMTest4.xml");
    125     common();
    126
    127     ControlFilter cf1 = new ControlFilter(new String[]{TEST1_1A_PAT, TEST1_1B_PAT,
    128 					       EXCEPTION1, EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
    129
    130     ControlFilter cf2 = new ControlFilter(new String[]{TEST1_2_PAT,
    131 					       EXCEPTION1, EXCEPTION2, EXCEPTION3, EXCEPTION4, EXCEPTION5});
    132
    133     Transformer.transform(
    134       TEMP_A1 + ".4", FILTERED_A1 + ".4",
    135       new Filter[] {
    136         cf1, new LineNumberFilter(), new SunReflectFilter(),
    137         new JunitTestRunnerFilter()
    138       });
    139
    140     Transformer.transform(
    141       TEMP_A2 + ".4", FILTERED_A2 + ".4",
    142       new Filter[] {
    143         cf2, new LineNumberFilter(), new ISO8601Filter(),
    144         new SunReflectFilter(), new JunitTestRunnerFilter()
    145       });
    146
    147     assertTrue(Compare.compare(FILTERED_A1 + ".4", "witness/dom.A1.4"));
    148     assertTrue(Compare.compare(FILTERED_A2 + ".4", "witness/dom.A2.4"));
    149   }
    150
    151   void common() {
    152     String oldThreadName = Thread.currentThread().getName();
    153     Thread.currentThread().setName("main");
    154
    155     int i = -1;
    156
    157     logger.trace("Message " + ++i);
    158     root.trace("Message " + i);
    159
    160     logger.debug("Message " + ++i);
    161     root.debug("Message " + i);
    162
    163     logger.info ("Message " + ++i);
    164     root.info("Message " + i);
    165
    166     logger.warn ("Message " + ++i);
    167     root.warn("Message " + i);
    168
    169     logger.error("Message " + ++i);
    170     root.error("Message " + i);
    171
    172     logger.log(Level.FATAL, "Message " + ++i);
    173     root.log(Level.FATAL, "Message " + i);
    174
    175     Exception e = new Exception("Just testing");
    176     logger.debug("Message " + ++i, e);
    177     root.debug("Message " + i, e);
    178
    179     logger.error("Message " + ++i, e);
    180     root.error("Message " + i, e);
    181
    182     Thread.currentThread().setName(oldThreadName);
    183   }
    184
    185
    186     /**
    187      * CustomLogger implementation for testCategoryFactory1 and 2.
    188      */
    189   private static class CustomLogger extends Logger {
    190         /**
    191          * Creates new instance.
    192          * @param name logger name.
    193          */
    194       public CustomLogger(final String name) {
    195           super(name);
    196       }
    197   }
    198
    199     /**
    200      * Creates new instances of CustomLogger.
    201      */
    202   public static class CustomLoggerFactory implements LoggerFactory {
    203         /**
    204          * Addivity, expected to be set false in configuration file.
    205          */
    206       private boolean additivity;
    207
    208         /**
    209          * Create new instance of factory.
    210          */
    211       public CustomLoggerFactory() {
    212           additivity = true;
    213       }
    214
    215         /**
    216          * Create new logger.
    217          * @param name logger name.
    218          * @return new logger.
    219          */
    220       public Logger makeNewLoggerInstance(final String name) {
    221           Logger logger = new CustomLogger(name);
    222           assertFalse(additivity);
    223           return logger;
    224       }
    225
    226         /**
    227          * Set additivity.
    228          * @param newVal new value of additivity.
    229          */
    230       public void setAdditivity(final boolean newVal) {
    231           additivity = newVal;
    232       }
    233   }
    234
    235     /**
    236      * CustomErrorHandler for testCategoryFactory2.
    237      */
    238   public static class CustomErrorHandler implements ErrorHandler {
    239       public CustomErrorHandler() {}
    240       public void activateOptions() {}
    241       public void setLogger(final Logger logger) {}
    242       public void error(String message, Exception e, int errorCode) {}
    243       public void error(String message) {}
    244       public void error(String message, Exception e, int errorCode, LoggingEvent event) {}
    245       public void setAppender(Appender appender) {}
    246       public void setBackupAppender(Appender appender) {}
    247   }
    248
    249     /**
    250      * Tests that loggers mentioned in logger elements
    251      *    use the specified categoryFactory.  See bug 33708.
    252      */
    253   public void testCategoryFactory1() {
    254       DOMConfigurator.configure("input/xml/categoryfactory1.xml");
    255       //
    256       //   logger explicitly mentioned in configuration,
    257       //         should be a CustomLogger
    258       Logger logger1 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testCategoryFactory1.1");
    259       assertTrue(logger1 instanceof CustomLogger);
    260       //
    261       //   logger not explicitly mentioned in configuration,
    262       //         should use default factory
    263       Logger logger2 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testCategoryFactory1.2");
    264       assertFalse(logger2 instanceof CustomLogger);
    265   }
    266
    267     /**
    268      * Tests that loggers mentioned in logger-ref elements
    269      *    use the specified categoryFactory.  See bug 33708.
    270      */
    271     public void testCategoryFactory2() {
    272         DOMConfigurator.configure("input/xml/categoryfactory2.xml");
    273         //
    274         //   logger explicitly mentioned in configuration,
    275         //         should be a CustomLogger
    276         Logger logger1 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testCategoryFactory2.1");
    277         assertTrue(logger1 instanceof CustomLogger);
    278         //
    279         //   logger not explicitly mentioned in configuration,
    280         //         should use default factory
    281         Logger logger2 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testCategoryFactory2.2");
    282         assertFalse(logger2 instanceof CustomLogger);
    283     }
    284
    285     /**
    286      * Tests that loggers mentioned in logger elements
    287      *    use the specified loggerFactory.  See bug 33708.
    288      */
    289   public void testLoggerFactory1() {
    290       DOMConfigurator.configure("input/xml/loggerfactory1.xml");
    291       //
    292       //   logger explicitly mentioned in configuration,
    293       //         should be a CustomLogger
    294       Logger logger1 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testLoggerFactory1.1");
    295       assertTrue(logger1 instanceof CustomLogger);
    296       //
    297       //   logger not explicitly mentioned in configuration,
    298       //         should use default factory
    299       Logger logger2 = Logger.getLogger("org.apache.log4j.xml.DOMTestCase.testLoggerFactory1.2");
    300       assertFalse(logger2 instanceof CustomLogger);
    301   }
    302
    303     /**
    304      * Tests that reset="true" on log4j:configuration element resets
    305      * repository before configuration.
    306      * @throws Exception thrown on error.
    307      */
    308   public void testReset() throws Exception {
    309       VectorAppender appender = new VectorAppender();
    310       appender.setName("V1");
    311       Logger.getRootLogger().addAppender(appender);
    312       DOMConfigurator.configure("input/xml/testReset.xml");
    313       assertNull(Logger.getRootLogger().getAppender("V1"));
    314   }
    315
    316
    317     /**
    318      * Test checks that configureAndWatch does initial configuration, see bug 33502.
    319       * @throws Exception if IO error.
    320      */
    321   public void testConfigureAndWatch() throws Exception {
    322     DOMConfigurator.configureAndWatch("input/xml/DOMTestCase1.xml");
    323     assertNotNull(Logger.getRootLogger().getAppender("A1"));
    324   }
    325
    326
    327     /**
    328      * This test checks that the subst method of an extending class
    329      * is checked when evaluating parameters.  See bug 43325.
    330      *
    331      */
    332   public void testOverrideSubst() {
    333       DOMConfigurator configurator = new DOMConfigurator() {
    334           protected String subst(final String value) {
    335               if ("output/temp.A1".equals(value)) {
    336                   return "output/subst-test.A1";
    337               }
    338               return value;
    339           }
    340       };
    341       configurator.doConfigure("input/xml/DOMTestCase1.xml", LogManager.getLoggerRepository());
    342       FileAppender a1 = (FileAppender) Logger.getRootLogger().getAppender("A1");
    343       String file = a1.getFile();
    344       assertEquals("output/subst-test.A1", file);
    345   }
    346
    347     /**
    348      * Mock ThrowableRenderer for testThrowableRenderer.  See bug 45721.
    349      */
    350     public static class MockThrowableRenderer implements ThrowableRenderer, OptionHandler {
    351         private boolean activated = false;
    352         private boolean showVersion = true;
    353
    354         public MockThrowableRenderer() {
    355         }
    356
    357         public void activateOptions() {
    358             activated = true;
    359         }
    360
    361         public boolean isActivated() {
    362             return activated;
    363         }
    364
    365         public String[] doRender(final Throwable t) {
    366             return new String[0];
    367         }
    368
    369         public void setShowVersion(boolean v) {
    370             showVersion = v;
    371         }
    372
    373         public boolean getShowVersion() {
    374             return showVersion;
    375         }
    376     }
    377
    378     /**
    379      * Test of log4j.throwableRenderer support.  See bug 45721.
    380      */
    381     public void testThrowableRenderer1() {
    382         DOMConfigurator.configure("input/xml/throwableRenderer1.xml");
    383         ThrowableRendererSupport repo = (ThrowableRendererSupport) LogManager.getLoggerRepository();
    384         MockThrowableRenderer renderer = (MockThrowableRenderer) repo.getThrowableRenderer();
    385         LogManager.resetConfiguration();
    386         assertNotNull(renderer);
    387         assertEquals(true, renderer.isActivated());
    388         assertEquals(false, renderer.getShowVersion());
    389     }
    390
    391     /**
    392      * Test for bug 47465.
    393      * configure(URL) did not close opened JarURLConnection.
    394      * @throws IOException if IOException creating properties jar.
    395      */
    396     public void testJarURL() throws IOException {
    397         File input = new File("input/xml/defaultInit.xml");
    398         System.out.println(input.getAbsolutePath());
    399         InputStream is = new FileInputStream(input);
    400         File dir = new File("output");
    401         dir.mkdirs();
    402         File file = new File("output/xml.jar");
    403         ZipOutputStream zos =
    404             new ZipOutputStream(new FileOutputStream(file));
    405         zos.putNextEntry(new ZipEntry("log4j.xml"));
    406         int len;
    407         byte[] buf = new byte[1024];
    408         while ((len = is.read(buf)) > 0) {
    409             zos.write(buf, 0, len);
    410         }
    411         zos.closeEntry();
    412         zos.close();
    413         URL url = new URL("jar:" + file.toURL() + "!/log4j.xml");
    414         DOMConfigurator.configure(url);
    415         assertTrue(file.delete());
    416         assertFalse(file.exists());
    417     }
    418
    419 }