View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.joran;
15  
16  import static org.junit.Assert.assertEquals;
17  import static org.junit.Assert.assertFalse;
18  import static org.junit.Assert.assertNotNull;
19  import static org.junit.Assert.assertNull;
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.IOException;
23  import java.text.SimpleDateFormat;
24  import java.util.Date;
25  
26  import org.junit.Ignore;
27  import org.junit.Test;
28  import org.slf4j.MDC;
29  import org.slf4j.event.KeyValuePair;
30  
31  import ch.qos.logback.classic.AsyncAppender;
32  import ch.qos.logback.classic.ClassicTestConstants;
33  import ch.qos.logback.classic.Level;
34  import ch.qos.logback.classic.Logger;
35  import ch.qos.logback.classic.LoggerContext;
36  import ch.qos.logback.classic.jul.JULHelper;
37  import ch.qos.logback.classic.spi.ILoggingEvent;
38  import ch.qos.logback.classic.turbo.DebugUsersTurboFilter;
39  import ch.qos.logback.classic.turbo.NOPTurboFilter;
40  import ch.qos.logback.classic.turbo.TurboFilter;
41  import ch.qos.logback.core.ConsoleAppender;
42  import ch.qos.logback.core.CoreConstants;
43  import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
44  import ch.qos.logback.core.joran.action.ParamAction;
45  import ch.qos.logback.core.joran.spi.ActionException;
46  import ch.qos.logback.core.joran.spi.JoranException;
47  import ch.qos.logback.core.pattern.parser.Parser;
48  import ch.qos.logback.core.read.ListAppender;
49  import ch.qos.logback.core.spi.ErrorCodes;
50  import ch.qos.logback.core.spi.ScanException;
51  import ch.qos.logback.core.status.Status;
52  import ch.qos.logback.core.testUtil.RandomUtil;
53  import ch.qos.logback.core.testUtil.StatusChecker;
54  import ch.qos.logback.core.testUtil.StringListAppender;
55  import ch.qos.logback.core.util.CachingDateFormatter;
56  import ch.qos.logback.core.util.StatusPrinter;
57  
58  public class JoranConfiguratorTest {
59  
60      LoggerContext loggerContext = new LoggerContext();
61      Logger logger = loggerContext.getLogger(this.getClass().getName());
62      Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
63      StatusChecker checker = new StatusChecker(loggerContext);
64      int diff = RandomUtil.getPositiveInt();
65  
66      void configure(String file) throws JoranException {
67          JoranConfigurator jc = new JoranConfigurator();
68          jc.setContext(loggerContext);
69          loggerContext.putProperty("diff", "" + diff);
70          jc.doConfigure(file);
71  
72      }
73  
74      @Test
75      public void simpleList() throws JoranException {
76          configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleList.xml");
77          Logger logger = loggerContext.getLogger(this.getClass().getName());
78          Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
79          ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
80          assertNotNull(listAppender);
81          assertEquals(0, listAppender.list.size());
82          String msg = "hello world";
83          logger.debug(msg);
84          assertEquals(1, listAppender.list.size());
85          ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
86          assertEquals(msg, le.getMessage());
87      }
88  
89  
90      @Test
91      public void asyncWithMultipleAppendersInRoot() throws JoranException {
92          configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "async/logback_1614.xml");
93          Logger logger = loggerContext.getLogger(this.getClass().getName());
94          Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
95          AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
96          assertNotNull(asyncAppender);
97          ConsoleAppender<ILoggingEvent> console = (ConsoleAppender<ILoggingEvent>) root.getAppender("CONSOLE");
98          assertNotNull(console);
99          assertTrue(console.isStarted());
100         //assertEquals(0, listAppender.list.size());
101         String msg = "hello world";
102         logger.warn(msg);
103         StatusPrinter.print(loggerContext);
104     }
105     
106     @Test
107     public void simpleListWithImports() throws JoranException {
108         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleListWithImports.xml");
109         Logger logger = loggerContext.getLogger(this.getClass().getName());
110         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
111         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
112         assertNotNull(listAppender);
113         assertEquals(0, listAppender.list.size());
114         String msg = "hello world";
115         logger.debug(msg);
116         assertEquals(1, listAppender.list.size());
117         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
118         assertEquals(msg, le.getMessage());
119     }
120 
121     @Test
122     public void level() throws JoranException {
123         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleLevel.xml");
124         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
125         assertEquals(0, listAppender.list.size());
126         String msg = "hello world";
127         logger.debug(msg);
128         assertEquals(0, listAppender.list.size());
129     }
130 
131     @Test
132     public void additivity() throws JoranException {
133         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "additivity.xml");
134         Logger logger = loggerContext.getLogger("additivityTest");
135         assertFalse(logger.isAdditive());
136     }
137 
138     @Test
139     public void rootLoggerLevelSettingBySystemProperty() throws JoranException {
140         String propertyName = "logback.level";
141 
142         System.setProperty(propertyName, "INFO");
143         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "rootLevelByProperty.xml");
144         // StatusPrinter.print(loggerContext);
145         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
146         assertEquals(0, listAppender.list.size());
147         String msg = "hello world";
148         logger.debug(msg);
149         assertEquals(0, listAppender.list.size());
150         System.clearProperty(propertyName);
151     }
152 
153     @Test
154     public void loggerLevelSettingBySystemProperty() throws JoranException {
155         String propertyName = "logback.level";
156         System.setProperty(propertyName, "DEBUG");
157         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "loggerLevelByProperty.xml");
158         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
159         assertEquals(0, listAppender.list.size());
160         String msg = "hello world";
161         logger.debug(msg);
162         assertEquals(1, listAppender.list.size());
163         System.clearProperty(propertyName);
164     }
165 
166     @Test
167     public void appenderRefSettingBySystemProperty() throws JoranException {
168         final String propertyName = "logback.appenderRef";
169         System.setProperty(propertyName, "A");
170         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "appenderRefByProperty.xml");
171         final Logger logger = loggerContext.getLogger("ch.qos.logback.classic.joran");
172         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) logger.getAppender("A");
173         assertEquals(0, listAppender.list.size());
174         final String msg = "hello world";
175         logger.info(msg);
176 
177         assertEquals(1, listAppender.list.size());
178         System.clearProperty(propertyName);
179     }
180 
181     @Test
182     public void statusListener() throws JoranException {
183         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "statusListener.xml");
184         checker.assertIsErrorFree();
185         checker.assertContainsMatch(Status.WARN,
186                 "Please use \"level\" attribute within <logger> or <root> elements instead.");
187     }
188 
189     @Test
190     public void statusListenerWithImports() throws JoranException {
191         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "statusListenerWithImports.xml");
192         //StatusPrinter.print(loggerContext);
193         checker.assertIsErrorFree();
194         checker.assertContainsMatch(Status.WARN,
195                 "Please use \"level\" attribute within <logger> or <root> elements instead.");
196     }
197 
198     @Test
199     public void contextRename() throws JoranException {
200         loggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME);
201         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "contextRename.xml");
202         assertEquals("wombat", loggerContext.getName());
203     }
204 
205     @Test
206     public void eval() throws JoranException {
207         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "callerData.xml");
208         String msg = "hello world";
209         logger.debug("toto");
210         logger.debug(msg);
211 
212         StringListAppender<ILoggingEvent> slAppender = (StringListAppender<ILoggingEvent>) loggerContext
213                 .getLogger("root").getAppender("STR_LIST");
214         assertNotNull(slAppender);
215         assertEquals(2, slAppender.strList.size());
216         assertTrue(slAppender.strList.get(0).contains(" DEBUG - toto"));
217 
218         String str1 = slAppender.strList.get(1);
219         assertTrue(str1.contains("Caller+0"));
220         assertTrue(str1.contains(" DEBUG - hello world"));
221     }
222 
223     
224     @Test
225     public void missingConfigurationElement() throws JoranException {
226         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/noConfig.xml");
227         
228         String msg1 = "Exception in body\\(\\) method for action \\["+ParamAction.class.getName()+"\\]";
229         checker.assertContainsMatch(Status.ERROR, msg1);
230         
231         String msg2 = "current model is null. Is <configuration> element missing?";
232         checker.assertContainsException(ActionException.class, msg2 );
233     }
234 
235     @Test
236     public void ignoreUnknownProperty() throws JoranException {
237         
238         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/unknownProperty.xml");
239         String msg = "Ignoring unkown property \\[a\\] in \\[ch.qos.logback.classic.LoggerContext\\]";
240         checker.assertContainsMatch(Status.WARN, msg);
241     }
242     
243     // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46995
244     @Test
245     public void complexCollectionWihhNoKnownClass() throws JoranException {
246         
247        configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/nestedComplexWithNoKnownClass.xml");
248        String msg = "Could not find an appropriate class for property \\[listener\\]";
249        checker.assertContainsMatch(Status.ERROR, msg);
250     }
251     
252     @Test
253     public void turboFilter() throws JoranException {
254         // Although this test uses turbo filters, it only checks
255         // that Joran can see the xml element and create
256         // and place the relevant object correctly.
257         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo.xml");
258 
259         TurboFilter filter = loggerContext.getTurboFilterList().get(0);
260         assertTrue(filter instanceof NOPTurboFilter);
261     }
262 
263     @Test
264     public void testTurboFilterWithStringList() throws JoranException {
265         // Although this test uses turbo filters, it only checks
266         // that Joran can see <user> elements, and behave correctly
267         // that is call the addUser method and pass the correct values
268         // to that method.
269         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo2.xml");
270 
271         // StatusPrinter.print(loggerContext.getStatusManager());
272 
273         TurboFilter filter = loggerContext.getTurboFilterList().get(0);
274         assertTrue(filter instanceof DebugUsersTurboFilter);
275         DebugUsersTurboFilter dutf = (DebugUsersTurboFilter) filter;
276         assertEquals(2, dutf.getUsers().size());
277     }
278 
279     @Test
280     public void testLevelFilter() throws JoranException {
281         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "levelFilter.xml");
282 
283         // StatusPrinter.print(loggerContext);
284 
285         logger.warn("hello");
286         logger.error("to be ignored");
287 
288         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
289 
290         assertNotNull(listAppender);
291         assertEquals(1, listAppender.list.size());
292         ILoggingEvent back = listAppender.list.get(0);
293         assertEquals(Level.WARN, back.getLevel());
294         assertEquals("hello", back.getMessage());
295     }
296 
297     @Test
298     public void testEvaluatorFilter() throws JoranException {
299         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "evaluatorFilter.xml");
300 
301         // StatusPrinter.print(loggerContext);
302 
303         logger.warn("hello");
304         logger.error("to be ignored");
305 
306         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
307 
308         assertNotNull(listAppender);
309         assertEquals(1, listAppender.list.size());
310         ILoggingEvent back = listAppender.list.get(0);
311         assertEquals(Level.WARN, back.getLevel());
312         assertEquals("hello", back.getMessage());
313     }
314 
315     @Test
316     public void testEvaluatorFilterWithImports() throws JoranException {
317         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "evaluatorFilterWithImports.xml");
318 
319         // StatusPrinter.print(loggerContext);
320 
321         logger.warn("hello");
322         logger.error("to be ignored");
323 
324         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
325 
326         assertNotNull(listAppender);
327         assertEquals(1, listAppender.list.size());
328         ILoggingEvent back = listAppender.list.get(0);
329         assertEquals(Level.WARN, back.getLevel());
330         assertEquals("hello", back.getMessage());
331     }
332 
333     @Test
334     public void testTurboDynamicThreshold() throws JoranException {
335         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold.xml");
336 
337         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
338         assertEquals(0, listAppender.list.size());
339 
340         // this one should be denied
341         MDC.put("userId", "user1");
342         logger.debug("hello user1");
343         // this one should log
344         MDC.put("userId", "user2");
345         logger.debug("hello user2");
346 
347         assertEquals(1, listAppender.list.size());
348         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
349         assertEquals("hello user2", le.getMessage());
350     }
351 
352     @Test
353     public void testTurboDynamicThreshold2() throws JoranException {
354 
355         try {
356             configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold2.xml");
357         } finally {
358             // StatusPrinter.print(loggerContext);
359         }
360         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
361         assertEquals(0, listAppender.list.size());
362 
363         // this one should log
364         MDC.put("userId", "user1");
365         logger.debug("hello user1");
366         // this one should log
367         MDC.put("userId", "user2");
368         logger.debug("hello user2");
369         // this one should fail
370         MDC.put("userId", "user3");
371         logger.debug("hello user3");
372 
373         assertEquals(2, listAppender.list.size());
374         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
375         assertEquals("hello user1", le.getMessage());
376         le = (ILoggingEvent) listAppender.list.get(1);
377         assertEquals("hello user2", le.getMessage());
378     }
379 
380     @Test
381     public void timestamp() throws JoranException, IOException, InterruptedException {
382 
383         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-context.xml";
384         configure(configFileAsStr);
385 
386         String r = loggerContext.getProperty("testTimestamp");
387         assertNotNull(r);
388         CachingDateFormatter sdf = new CachingDateFormatter("yyyy-MM");
389         String expected = sdf.format(System.currentTimeMillis());
390         assertEquals("expected \"" + expected + "\" but got " + r, expected, r);
391     }
392 
393     @Test
394     public void timestampLocal() throws JoranException, IOException, InterruptedException {
395 
396         String sysProp = "ch.qos.logback.classic.joran.JoranConfiguratorTest.timestampLocal";
397         System.setProperty(sysProp, "");
398 
399         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-local.xml";
400         configure(configFileAsStr);
401 
402         // It's hard to test the local variable has been set, as it's not
403         // visible from here. But instead we test that it's not set in the
404         // context. And check that a system property has been replaced with the
405         // contents of the local variable
406 
407         String r = loggerContext.getProperty("testTimestamp");
408         assertNull(r);
409 
410         String expected = "today is " + new SimpleDateFormat("yyyy-MM").format(new Date());
411         String sysPropValue = System.getProperty(sysProp);
412         assertEquals(expected, sysPropValue);
413     }
414 
415     @Test
416     public void encoderCharset() throws JoranException, IOException, InterruptedException {
417 
418         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "encoderCharset.xml";
419         configure(configFileAsStr);
420 
421         ConsoleAppender<ILoggingEvent> consoleAppender = (ConsoleAppender<ILoggingEvent>) root.getAppender("CONSOLE");
422         assertNotNull(consoleAppender);
423         LayoutWrappingEncoder<ILoggingEvent> encoder = (LayoutWrappingEncoder<ILoggingEvent>) consoleAppender
424                 .getEncoder();
425 
426         assertEquals("UTF-8", encoder.getCharset().displayName());
427 
428         checker.assertIsErrorFree();
429     }
430 
431     void verifyJULLevel(String loggerName, Level expectedLevel) {
432         java.util.logging.Logger julLogger = JULHelper.asJULLogger(loggerName);
433         java.util.logging.Level julLevel = julLogger.getLevel();
434 
435         if (expectedLevel == null) {
436             assertNull(julLevel);
437         } else {
438             assertEquals(JULHelper.asJULLevel(expectedLevel), julLevel);
439         }
440 
441     }
442 
443     @Test
444     public void levelChangePropagator0() throws JoranException, IOException, InterruptedException {
445         String loggerName = "changePropagator0" + diff;
446         java.util.logging.Logger.getLogger(loggerName).setLevel(java.util.logging.Level.INFO);
447         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/jul/levelChangePropagator0.xml";
448         configure(configFileAsStr);
449 
450         checker.assertIsErrorFree();
451         verifyJULLevel(loggerName, null);
452         verifyJULLevel("a.b.c." + diff, Level.WARN);
453         verifyJULLevel(Logger.ROOT_LOGGER_NAME, Level.TRACE);
454     }
455 
456     @Test
457     public void levelChangePropagator1() throws JoranException, IOException, InterruptedException {
458         String loggerName = "changePropagator1" + diff;
459         java.util.logging.Logger logger1 = java.util.logging.Logger.getLogger(loggerName);
460         logger1.setLevel(java.util.logging.Level.INFO);
461         verifyJULLevel(loggerName, Level.INFO);
462         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/jul/levelChangePropagator1.xml";
463         configure(configFileAsStr);
464 
465         checker.assertIsErrorFree();
466         verifyJULLevel(loggerName, Level.INFO); //
467         verifyJULLevel("a.b.c." + diff, Level.WARN);
468         verifyJULLevel(Logger.ROOT_LOGGER_NAME, Level.TRACE);
469     }
470 
471     @Test
472     @Ignore
473     public void onConsoleRetro() throws JoranException, IOException, InterruptedException {
474         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/onConsoleRetro.xml";
475         configure(configFileAsStr);
476         Thread.sleep(400);
477 
478         loggerContext.reset();
479         configure(configFileAsStr);
480     }
481 
482     @Test
483     public void unreferencedAppenderShouldNotTriggerUnknownPropertyMessages() throws JoranException {
484         String configFileAsStr = ClassicTestConstants.ISSUES_PREFIX + "/logback1572.xml";
485         configure(configFileAsStr);
486         checker.assertContainsMatch(Status.WARN,
487                 "Appender named \\[EMAIL\\] not referenced. Skipping further processing.");
488         checker.assertNoMatch("Ignoring unkown property \\[evaluator\\]");
489     }
490 
491     @Test
492     public void LOGBACK_111() throws JoranException {
493         String configFileAsStr = ClassicTestConstants.ISSUES_PREFIX + "lbcore193.xml";
494         configure(configFileAsStr);
495         checker.assertContainsException(ScanException.class);
496         checker.assertContainsMatch(Status.ERROR, "Expecting RIGHT_PARENTHESIS token but got null");
497         checker.assertContainsMatch(Status.ERROR, "See also " + Parser.MISSING_RIGHT_PARENTHESIS);
498     }
499 
500     @Test
501     public void properties() throws JoranException {
502         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "properties.xml";
503         assertNull(System.getProperty("sys"));
504 
505         configure(configFileAsStr);
506         assertNotNull(loggerContext.getProperty(CoreConstants.HOSTNAME_KEY));
507         assertNull(loggerContext.getProperty("transientKey1"));
508         assertNull(loggerContext.getProperty("transientKey2"));
509         assertEquals("node0", loggerContext.getProperty("nodeId"));
510         assertEquals("tem", System.getProperty("sys"));
511         assertNotNull(loggerContext.getProperty("path"));
512         checker.assertIsErrorFree();
513     }
514 
515     @Test
516     public void hostnameProperty() throws JoranException {
517         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "hostnameProperty.xml";
518         configure(configFileAsStr);
519         assertEquals("A", loggerContext.getProperty(CoreConstants.HOSTNAME_KEY));
520     }
521 
522     // see also http://jira.qos.ch/browse/LOGBACK-134
523     @Test
524     public void sysProps() throws JoranException {
525         System.setProperty("k.lbcore254", ClassicTestConstants.ISSUES_PREFIX + "lbcore254");
526         JoranConfigurator configurator = new JoranConfigurator();
527         configurator.setContext(loggerContext);
528         configurator.doConfigure(ClassicTestConstants.ISSUES_PREFIX + "lbcore254.xml");
529 
530         checker.assertIsErrorFree();
531     }
532 
533     @Test
534     public void propsWithMissingRightCurlyBrace() throws JoranException {
535         System.setProperty("abc", "not important");
536         JoranConfigurator configurator = new JoranConfigurator();
537         configurator.setContext(loggerContext);
538         configurator.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "propsMissingRightCurlyBrace.xml");
539         checker.assertContainsMatch(Status.ERROR, "Problem while parsing");
540     }
541 
542     @Test
543     public void packageDataDisabledByConfigAttribute() throws JoranException {
544         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataDisabled.xml";
545         configure(configFileAsStr);
546         assertFalse(loggerContext.isPackagingDataEnabled());
547     }
548 
549     @Test
550     public void packageDataEnabledByConfigAttribute() throws JoranException {
551         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataEnabled.xml";
552         try {
553             configure(configFileAsStr);
554         } finally {
555             // StatusPrinter.print(loggerContext);
556         }
557         assertTrue(loggerContext.isPackagingDataEnabled());
558     }
559 
560     @Test
561     public void valueOfConvention() throws JoranException {
562         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "valueOfConvention.xml";
563         configure(configFileAsStr);
564         checker.assertIsWarningOrErrorFree();
565     }
566 
567     @Test
568     public void shutdownHookTest() throws JoranException {
569         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1162.xml";
570         loggerContext.putProperty("output_dir", ClassicTestConstants.OUTPUT_DIR_PREFIX + "logback_issue_1162/");
571         configure(configFileAsStr);
572         assertNotNull(loggerContext.getObject(CoreConstants.SHUTDOWN_HOOK_THREAD));
573     }
574 
575     @Test
576     public void appenderRefBeforeAppenderTest() throws JoranException {
577         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "appenderRefBeforeAppender.xml";
578         configure(configFileAsStr);
579         Logger logger = loggerContext.getLogger(this.getClass().getName());
580         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
581         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
582         assertNotNull(listAppender);
583         assertEquals(0, listAppender.list.size());
584         String msg = "hello world";
585         logger.debug(msg);
586         assertEquals(1, listAppender.list.size());
587         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
588         assertEquals(msg, le.getMessage());
589         checker.assertIsErrorFree();
590     }
591 
592     @Test
593     public void unreferencedAppendersShouldBeSkipped() throws JoranException {
594         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "unreferencedAppender1.xml");
595 
596         final ListAppender<ILoggingEvent> listAppenderA = (ListAppender<ILoggingEvent>) root.getAppender("A");
597         assertNotNull(listAppenderA);
598         checker.assertContainsMatch(Status.WARN, "Appender named \\[B\\] not referenced. Skipping further processing.");
599     }
600 
601     @Test
602     public void asynAppenderListFirst() throws JoranException {
603         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "asyncAppender_list_first.xml");
604 
605         final AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
606         assertNotNull(asyncAppender);
607         assertTrue(asyncAppender.isStarted());
608     }
609 
610     @Test
611     public void asynAppenderListAfter() throws JoranException {
612         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "asyncAppender_list_after.xml");
613 
614         final AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
615         assertNotNull(asyncAppender);
616         assertTrue(asyncAppender.isStarted());
617     }
618 
619     // https://jira.qos.ch/browse/LOGBACK-1570
620     @Test
621     public void missingPropertyErrorHandling() throws JoranException {
622         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "missingProperty.xml");
623 
624         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
625         assertNotNull(listAppender);
626         assertTrue(listAppender.isStarted());
627         checker.assertContainsMatch(Status.WARN,
628                 "Ignoring unkown property \\[inexistent\\] in \\[ch.qos.logback.core.read.ListAppender\\]");
629     }
630 
631     @Test
632     public void kvp() throws JoranException {
633         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "pattern/kvp.xml");
634 
635         String msg = "hello kvp";
636 
637         KeyValuePair kvp1 = new KeyValuePair("k" + diff, "v" + diff);
638         KeyValuePair kvp2 = new KeyValuePair("k" + (diff + 1), "v" + (diff + 1));
639         KeyValuePair kvpNullKey = new KeyValuePair(null, "v" + (diff + 2));
640         KeyValuePair kvpNullValue = new KeyValuePair("k" + (diff + 3), null);
641 
642         logger.atDebug().addKeyValue(kvp1.key, kvp1.value).log(msg);
643         logger.atDebug().addKeyValue(kvp2.key, kvp2.value).log(msg);
644         logger.atDebug().addKeyValue(kvpNullKey.key, kvpNullKey.value).log(msg);
645         logger.atDebug().addKeyValue(kvpNullValue.key, kvpNullValue.value).log(msg);
646 
647         StringListAppender<ILoggingEvent> slAppender = (StringListAppender<ILoggingEvent>) loggerContext
648                 .getLogger("root").getAppender("LIST");
649         assertNotNull(slAppender);
650         assertEquals(4, slAppender.strList.size());
651         assertTrue(slAppender.strList.get(0).contains(kvp1.key + "=\"" + kvp1.value + "\" " + msg));
652         assertTrue(slAppender.strList.get(1).contains(kvp2.key + "=\"" + kvp2.value + "\" " + msg));
653         assertTrue(slAppender.strList.get(2).contains("null=\"" + kvpNullKey.value + "\" " + msg));
654         assertTrue(slAppender.strList.get(3).contains(kvpNullValue.key + "=\"null\" " + msg));
655     }
656  
657     
658     // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=46697
659     @Test
660     public void ossFuzz_46697() throws JoranException  {
661         System.out.println("==========");
662         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-46697.xml");
663          
664         checker.assertContainsMatch(Status.ERROR, ErrorCodes.EMPTY_MODEL_STACK);
665         StatusPrinter.print(loggerContext);
666     }  
667     
668 //	@Test
669 //	public void doTest() throws JoranException {
670 //		int LIMIT = 0;
671 //		boolean oss = true;
672 //		for (int i = 0; i < LIMIT; i++) {
673 //			innerDoT(oss);
674 //		}
675 //		long start = System.currentTimeMillis();
676 //		innerDoT(oss);
677 //		long diff = System.currentTimeMillis() - start;
678 //		double average = (1.0d * diff);
679 //		System.out.println("Average time " + average + " ms. By serialization " + oss);
680 //
681 //	}
682 
683 //	private void innerDoT(boolean oss) throws JoranException {
684 //		JoranConfigurator jc = new JoranConfigurator();
685 //		jc.setContext(loggerContext);
686 //		if (oss) {
687 //			System.out.println("jc.doT");
688 //			jc.doT();
689 //		} else {
690 //			System.out.println("jc.doConfigure");
691 //			jc.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "twoAppenders.xml");
692 //		}
693 //	}
694 
695 }