1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  package ch.qos.logback.classic.joran;
15  
16  import ch.qos.logback.classic.*;
17  import ch.qos.logback.classic.joran.serializedModel.HardenedModelInputStream;
18  import ch.qos.logback.classic.model.ConfigurationModel;
19  import ch.qos.logback.classic.model.LoggerModel;
20  import ch.qos.logback.classic.spi.ILoggingEvent;
21  import ch.qos.logback.classic.spi.LoggingEvent;
22  import ch.qos.logback.classic.turbo.DebugUsersTurboFilter;
23  import ch.qos.logback.classic.turbo.NOPTurboFilter;
24  import ch.qos.logback.classic.turbo.TurboFilter;
25  import ch.qos.logback.classic.util.LogbackMDCAdapter;
26  import ch.qos.logback.core.ConsoleAppender;
27  import ch.qos.logback.core.CoreConstants;
28  import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
29  import ch.qos.logback.core.joran.action.ParamAction;
30  import ch.qos.logback.core.joran.spi.ActionException;
31  import ch.qos.logback.core.joran.spi.JoranException;
32  import ch.qos.logback.core.model.Model;
33  import ch.qos.logback.core.model.SerializeModelModel;
34  import ch.qos.logback.core.pattern.parser.Parser;
35  import ch.qos.logback.core.read.ListAppender;
36  import ch.qos.logback.core.spi.ErrorCodes;
37  import ch.qos.logback.core.spi.ScanException;
38  import ch.qos.logback.core.status.Status;
39  import ch.qos.logback.core.status.testUtil.StatusChecker;
40  import ch.qos.logback.core.testUtil.RandomUtil;
41  import ch.qos.logback.core.testUtil.StringListAppender;
42  import ch.qos.logback.core.util.CachingDateFormatter;
43  import ch.qos.logback.core.util.EnvUtil;
44  import ch.qos.logback.core.util.StatusPrinter;
45  import ch.qos.logback.core.util.StatusPrinter2;
46  import org.junit.jupiter.api.Disabled;
47  import org.junit.jupiter.api.Test;
48  import org.slf4j.MDC;
49  import org.slf4j.event.KeyValuePair;
50  import org.slf4j.spi.MDCAdapter;
51  
52  import java.io.Console;
53  import java.io.FileInputStream;
54  import java.io.IOException;
55  import java.nio.charset.Charset;
56  import java.text.SimpleDateFormat;
57  import java.util.Date;
58  
59  import static ch.qos.logback.core.CoreConstants.MODEL_CONFIG_FILE_EXTENSION;
60  import static ch.qos.logback.core.joran.sanity.AppenderWithinAppenderSanityChecker.NESTED_APPENDERS_WARNING;
61  import static ch.qos.logback.core.model.processor.ImplicitModelHandler.IGNORING_UNKNOWN_PROP;
62  import static ch.qos.logback.core.model.processor.ShutdownHookModelHandler.RENAME_WARNING;
63  import static ch.qos.logback.core.testUtil.CoreTestConstants.OUTPUT_DIR_PREFIX;
64  import static org.junit.jupiter.api.Assertions.*;
65  
66  public class JoranConfiguratorTest {
67  
68      LoggerContext loggerContext = new LoggerContext();
69      MDCAdapter mdcAdapter = new LogbackMDCAdapter();
70      Logger logger = loggerContext.getLogger(this.getClass().getName());
71      Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
72      StatusPrinter2 statusPrinter2 = new StatusPrinter2();
73      StatusChecker checker = new StatusChecker(loggerContext);
74      int diff = RandomUtil.getPositiveInt();
75  
76      void configure(String file) throws JoranException {
77          loggerContext.setMDCAdapter(mdcAdapter);
78          JoranConfigurator jc = new JoranConfigurator();
79          jc.setContext(loggerContext);
80          loggerContext.putProperty("diff", "" + diff);
81          jc.doConfigure(file);
82  
83      }
84  
85      @Test
86      public void simpleList() throws JoranException {
87          configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleList.xml");
88          Logger logger = loggerContext.getLogger(this.getClass().getName());
89          Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
90          ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
91          assertNotNull(listAppender);
92          assertEquals(0, listAppender.list.size());
93          String msg = "hello world";
94          logger.debug(msg);
95          assertEquals(1, listAppender.list.size());
96          ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
97          assertEquals(msg, le.getMessage());
98      }
99  
100 
101     @Test
102     public void asyncWithMultipleAppendersInRoot() throws JoranException {
103         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "async/logback_1614.xml");
104         Logger logger = loggerContext.getLogger(this.getClass().getName());
105         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
106         AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
107         assertNotNull(asyncAppender);
108         ConsoleAppender<ILoggingEvent> console = (ConsoleAppender<ILoggingEvent>) root.getAppender("CONSOLE");
109         assertNotNull(console);
110         assertTrue(console.isStarted());
111         
112         String msg = "hello world";
113         logger.warn(msg);
114     }
115 
116     @Test
117     public void simpleListWithImports() throws JoranException {
118         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleListWithImports.xml");
119         Logger logger = loggerContext.getLogger(this.getClass().getName());
120         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
121         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
122         assertNotNull(listAppender);
123         assertEquals(0, listAppender.list.size());
124         String msg = "hello world";
125         logger.debug(msg);
126         assertEquals(1, listAppender.list.size());
127         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
128         assertEquals(msg, le.getMessage());
129     }
130 
131     @Test
132     public void level() throws JoranException {
133         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleLevel.xml");
134         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
135         assertEquals(0, listAppender.list.size());
136         String msg = "hello world";
137         logger.debug(msg);
138         assertEquals(0, listAppender.list.size());
139     }
140 
141     @Test
142     public void additivity() throws JoranException {
143         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "additivity.xml");
144         Logger logger = loggerContext.getLogger("additivityTest");
145         assertFalse(logger.isAdditive());
146     }
147 
148     @Test
149     public void rootLoggerLevelSettingBySystemProperty() throws JoranException {
150         String propertyName = "logback.level";
151 
152         System.setProperty(propertyName, "INFO");
153         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "rootLevelByProperty.xml");
154         
155         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
156         assertEquals(0, listAppender.list.size());
157         String msg = "hello world";
158         logger.debug(msg);
159         assertEquals(0, listAppender.list.size());
160         System.clearProperty(propertyName);
161     }
162 
163     @Test
164     public void loggerLevelSettingBySystemProperty() throws JoranException {
165         String propertyName = "logback.level";
166         System.setProperty(propertyName, "DEBUG");
167         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "loggerLevelByProperty.xml");
168         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
169         assertEquals(0, listAppender.list.size());
170         String msg = "hello world";
171         logger.debug(msg);
172         assertEquals(1, listAppender.list.size());
173         System.clearProperty(propertyName);
174     }
175 
176     @Test
177     public void appenderRefSettingBySystemProperty() throws JoranException {
178         final String propertyName = "logback.appenderRef";
179         System.setProperty(propertyName, "A");
180         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "appenderRefByProperty.xml");
181         final Logger logger = loggerContext.getLogger("ch.qos.logback.classic.joran");
182         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) logger.getAppender("A");
183         assertEquals(0, listAppender.list.size());
184         final String msg = "hello world";
185         logger.info(msg);
186 
187         assertEquals(1, listAppender.list.size());
188         System.clearProperty(propertyName);
189     }
190 
191     @Test
192     public void statusListener() throws JoranException {
193         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "statusListener.xml");
194         
195         checker.assertIsErrorFree();
196         checker.assertContainsMatch(Status.WARN,
197                 "Please use \"level\" attribute within <logger> or <root> elements instead.");
198     }
199 
200     @Test
201     public void statusListenerWithImports() throws JoranException {
202         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "statusListenerWithImports.xml");
203         
204         checker.assertIsErrorFree();
205         checker.assertContainsMatch(Status.WARN,
206                 "Please use \"level\" attribute within <logger> or <root> elements instead.");
207     }
208 
209     @Test
210     public void contextRename() throws JoranException {
211         loggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME);
212         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "contextRename.xml");
213         assertEquals("wombat", loggerContext.getName());
214     }
215 
216     @Test
217     public void missingConfigurationElement() throws JoranException {
218         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/noConfig.xml");
219 
220         String msg1 = "Exception in body\\(\\) method for action \\[" + ParamAction.class.getName() + "\\]";
221         checker.assertContainsMatch(Status.ERROR, msg1);
222 
223         String msg2 = "current model is null. Is <configuration> element missing?";
224         checker.assertContainsException(ActionException.class, msg2);
225     }
226 
227     @Test
228     public void ignoreUnknownProperty() throws JoranException {
229 
230         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/unknownProperty.xml");
231         String msg = IGNORING_UNKNOWN_PROP + " \\[a\\] in \\[ch.qos.logback.classic.LoggerContext\\]";
232         checker.assertContainsMatch(Status.WARN, msg);
233     }
234 
235     
236     @Test
237     public void complexCollectionWihhNoKnownClass() throws JoranException {
238 
239         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/nestedComplexWithNoKnownClass.xml");
240         String msg = "Could not find an appropriate class for property \\[listener\\]";
241         checker.assertContainsMatch(Status.ERROR, msg);
242     }
243 
244     @Test
245     public void turboFilter() throws JoranException {
246         
247         
248         
249         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo.xml");
250 
251         TurboFilter filter = loggerContext.getTurboFilterList().get(0);
252         assertTrue(filter instanceof NOPTurboFilter);
253     }
254 
255     @Test
256     public void testTurboFilterWithStringList() throws JoranException {
257         
258         
259         
260         
261         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo2.xml");
262 
263         
264 
265         TurboFilter filter = loggerContext.getTurboFilterList().get(0);
266         assertTrue(filter instanceof DebugUsersTurboFilter);
267         DebugUsersTurboFilter dutf = (DebugUsersTurboFilter) filter;
268         assertEquals(2, dutf.getUsers().size());
269     }
270 
271     @Test
272     public void testLevelFilter() throws JoranException {
273         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "levelFilter.xml");
274 
275         
276 
277         logger.warn("hello");
278         logger.error("to be ignored");
279 
280         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
281 
282         assertNotNull(listAppender);
283         assertEquals(1, listAppender.list.size());
284         ILoggingEvent back = listAppender.list.get(0);
285         assertEquals(Level.WARN, back.getLevel());
286         assertEquals("hello", back.getMessage());
287     }
288 
289 
290     @Test
291     public void testTurboDynamicThreshold() throws JoranException {
292         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold.xml");
293 
294         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
295         assertEquals(0, listAppender.list.size());
296 
297         
298         MDC.put("userId", "user1");
299         logger.debug("hello user1");
300         
301         MDC.put("userId", "user2");
302         logger.debug("hello user2");
303 
304         assertEquals(1, listAppender.list.size());
305         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
306         assertEquals("hello user2", le.getMessage());
307     }
308 
309     @Test
310     public void testTurboDynamicThreshold2() throws JoranException {
311 
312         try {
313             configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold2.xml");
314         } finally {
315             
316         }
317         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
318         assertEquals(0, listAppender.list.size());
319 
320         
321         MDC.put("userId", "user1");
322         logger.debug("hello user1");
323         
324         MDC.put("userId", "user2");
325         logger.debug("hello user2");
326         
327         MDC.put("userId", "user3");
328         logger.debug("hello user3");
329 
330         assertEquals(2, listAppender.list.size());
331         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
332         assertEquals("hello user1", le.getMessage());
333         le = (ILoggingEvent) listAppender.list.get(1);
334         assertEquals("hello user2", le.getMessage());
335     }
336 
337     @Test
338     public void timestamp() throws JoranException, IOException, InterruptedException {
339 
340         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-context.xml";
341         configure(configFileAsStr);
342 
343         String r = loggerContext.getProperty("testTimestamp");
344         assertNotNull(r);
345         CachingDateFormatter sdf = new CachingDateFormatter("yyyy-MM");
346         String expected = sdf.format(System.currentTimeMillis());
347         assertEquals(expected, r, "expected \"" + expected + "\" but got " + r);
348     }
349 
350     @Test
351     public void timestampLocal() throws JoranException, IOException, InterruptedException {
352 
353         String sysProp = "ch.qos.logback.classic.joran.JoranConfiguratorTest.timestampLocal";
354         System.setProperty(sysProp, "");
355 
356         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-local.xml";
357         configure(configFileAsStr);
358 
359         
360         
361         
362         
363 
364         String r = loggerContext.getProperty("testTimestamp");
365         assertNull(r);
366 
367         String expected = "today is " + new SimpleDateFormat("yyyy-MM").format(new Date());
368         String sysPropValue = System.getProperty(sysProp);
369         assertEquals(expected, sysPropValue);
370     }
371 
372     @Test
373     public void encoderCharset() throws JoranException, IOException, InterruptedException {
374 
375         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "encoderCharset.xml";
376         configure(configFileAsStr);
377 
378         ConsoleAppender<ILoggingEvent> consoleAppender = (ConsoleAppender<ILoggingEvent>) root.getAppender("CONSOLE");
379         assertNotNull(consoleAppender);
380         LayoutWrappingEncoder<ILoggingEvent> encoder = (LayoutWrappingEncoder<ILoggingEvent>) consoleAppender
381                 .getEncoder();
382 
383         assertEquals("UTF-8", encoder.getCharset().displayName());
384 
385         checker.assertIsErrorFree();
386     }
387 
388 
389 
390     @Disabled 
391     @Test
392     public void onConsoleRetro() throws JoranException, IOException, InterruptedException {
393         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/onConsoleRetro.xml";
394         configure(configFileAsStr);
395         Thread.sleep(400);
396 
397         loggerContext.reset();
398         configure(configFileAsStr);
399     }
400 
401     @Test
402     public void unreferencedAppenderShouldNotTriggerUnknownPropertyMessages() throws JoranException {
403         String configFileAsStr = ClassicTestConstants.ISSUES_PREFIX + "/logback1572.xml";
404         configure(configFileAsStr);
405         checker.assertContainsMatch(Status.WARN,
406                 "Appender named \\[EMAIL\\] not referenced. Skipping further processing.");
407         checker.assertNoMatch(IGNORING_UNKNOWN_PROP + " \\[evaluator\\]");
408     }
409 
410     @Test
411     public void LOGBACK_111() throws JoranException {
412         String configFileAsStr = ClassicTestConstants.ISSUES_PREFIX + "lbcore193.xml";
413         configure(configFileAsStr);
414         checker.assertContainsException(ScanException.class);
415         checker.assertContainsMatch(Status.ERROR, "Expecting RIGHT_PARENTHESIS token but got null");
416         checker.assertContainsMatch(Status.ERROR, "See also " + Parser.MISSING_RIGHT_PARENTHESIS);
417     }
418 
419     @Test
420     public void properties() throws JoranException {
421         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "properties.xml";
422         assertNull(System.getProperty("sys"));
423 
424         configure(configFileAsStr);
425         assertNotNull(loggerContext.getProperty(CoreConstants.HOSTNAME_KEY));
426         assertNull(loggerContext.getProperty("transientKey1"));
427         assertNull(loggerContext.getProperty("transientKey2"));
428         assertEquals("node0", loggerContext.getProperty("nodeId"));
429         assertEquals("tem", System.getProperty("sys"));
430         assertNotNull(loggerContext.getProperty("path"));
431         checker.assertIsErrorFree();
432     }
433 
434     @Test
435     public void hostnameProperty() throws JoranException {
436         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "hostnameProperty.xml";
437         configure(configFileAsStr);
438         assertEquals("A", loggerContext.getProperty(CoreConstants.HOSTNAME_KEY));
439     }
440 
441     
442     @Test
443     public void sysProps() throws JoranException {
444         System.setProperty("k.lbcore254", ClassicTestConstants.ISSUES_PREFIX + "lbcore254");
445         JoranConfigurator configurator = new JoranConfigurator();
446         configurator.setContext(loggerContext);
447         configurator.doConfigure(ClassicTestConstants.ISSUES_PREFIX + "lbcore254.xml");
448 
449         checker.assertIsErrorFree();
450     }
451 
452     @Test
453     public void propsWithMissingRightCurlyBrace() throws JoranException {
454         System.setProperty("abc", "not important");
455         JoranConfigurator configurator = new JoranConfigurator();
456         configurator.setContext(loggerContext);
457         configurator.doConfigure(ClassicTestConstants.JORAN_INPUT_PREFIX + "propsMissingRightCurlyBrace.xml");
458         checker.assertContainsMatch(Status.ERROR, "Problem while parsing");
459     }
460 
461     @Test
462     public void packageDataDisabledByConfigAttribute() throws JoranException {
463         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataDisabled.xml";
464         configure(configFileAsStr);
465         assertFalse(loggerContext.isPackagingDataEnabled());
466     }
467 
468     @Test
469     public void packageDataEnabledByConfigAttribute() throws JoranException {
470         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataEnabled.xml";
471         try {
472             configure(configFileAsStr);
473         } finally {
474             
475         }
476         assertTrue(loggerContext.isPackagingDataEnabled());
477     }
478 
479     @Test
480     public void valueOfConvention() throws JoranException {
481         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "valueOfConvention.xml";
482         configure(configFileAsStr);
483         checker.assertIsWarningOrErrorFree();
484     }
485 
486     @Test
487     public void shutdownHookTest() throws JoranException {
488         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1162.xml";
489         loggerContext.putProperty("output_dir", ClassicTestConstants.OUTPUT_DIR_PREFIX + "logback_issue_1162/");
490         configure(configFileAsStr);
491         Thread thread = (Thread) loggerContext.getObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
492         assertNotNull(thread);
493     }
494 
495 
496     @Test
497     public void nestedAppendersDisallowed() throws JoranException {
498         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1674.xml";
499         configure(configFileAsStr);
500         checker.assertContainsMatch(Status.WARN, NESTED_APPENDERS_WARNING);
501         checker.assertContainsMatch(Status.WARN, "Appender at line ");
502     }
503 
504     @Test
505     public void shutdownHookWithDelayParameter() throws JoranException {
506         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1672.xml";
507         configure(configFileAsStr);
508 
509         Thread thread = (Thread) loggerContext.getObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
510         assertNotNull(thread);
511         checker.assertNoMatch(IGNORING_UNKNOWN_PROP);
512     }
513 
514     @Test
515     public void migrateShutdownHookClassName() throws JoranException {
516         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1678_shutdown.xml";
517         configure(configFileAsStr);
518 
519         Thread thread = (Thread) loggerContext.getObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
520         assertNotNull(thread);
521         checker.assertContainsMatch(RENAME_WARNING);
522     }
523 
524     @Test
525     public void appenderRefBeforeAppenderTest() throws JoranException {
526         String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "appenderRefBeforeAppender.xml";
527         configure(configFileAsStr);
528         Logger logger = loggerContext.getLogger(this.getClass().getName());
529         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
530         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
531         assertNotNull(listAppender);
532         assertEquals(0, listAppender.list.size());
533         String msg = "hello world";
534         logger.debug(msg);
535         assertEquals(1, listAppender.list.size());
536         ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0);
537         assertEquals(msg, le.getMessage());
538         checker.assertIsErrorFree();
539     }
540 
541     @Test
542     public void unreferencedAppendersShouldBeSkipped() throws JoranException {
543         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "unreferencedAppender1.xml");
544 
545         final ListAppender<ILoggingEvent> listAppenderA = (ListAppender<ILoggingEvent>) root.getAppender("A");
546         assertNotNull(listAppenderA);
547         checker.assertContainsMatch(Status.WARN, "Appender named \\[B\\] not referenced. Skipping further processing.");
548     }
549 
550     @Test
551     public void asynAppenderListFirst() throws JoranException {
552         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "asyncAppender_list_first.xml");
553 
554         final AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
555         assertNotNull(asyncAppender);
556         assertTrue(asyncAppender.isStarted());
557     }
558 
559     @Test
560     public void asynAppenderListAfter() throws JoranException {
561         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "asyncAppender_list_after.xml");
562 
563         final AsyncAppender asyncAppender = (AsyncAppender) root.getAppender("ASYNC");
564         assertNotNull(asyncAppender);
565         assertTrue(asyncAppender.isStarted());
566     }
567 
568     
569     @Test
570     public void missingPropertyErrorHandling() throws JoranException {
571         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "missingProperty.xml");
572 
573         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
574         assertNotNull(listAppender);
575         assertTrue(listAppender.isStarted());
576         checker.assertContainsMatch(Status.WARN,
577                 IGNORING_UNKNOWN_PROP + " \\[inexistent\\] in \\[ch.qos.logback.core.read.ListAppender\\]");
578     }
579 
580     @Test
581     public void sequenceNumberGenerator() throws JoranException {
582         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "sequenceNumberGenerator.xml");
583         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
584         assertNotNull(listAppender);
585 
586         logger.atDebug().setMessage("hello").log();
587         logger.atDebug().setMessage("world").log();
588 
589         ILoggingEvent le0 = listAppender.list.get(0);
590         ILoggingEvent le1 = listAppender.list.get(1);
591 
592         long se0 = le0.getSequenceNumber();
593         long se1 = le1.getSequenceNumber();
594         assertEquals(1, se1 - se0);
595     }
596 
597     @Test
598     public void sequenceNumberGenerator_missingClass() throws JoranException {
599         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "sequenceNumberGenerator-missingClass.xml");
600         
601         final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
602         assertNotNull(listAppender);
603         checker.assertContainsMatch(Status.ERROR, "Missing attribute \\[class\\]. See element \\[sequenceNumberGenerator\\]");
604     }
605 
606     @Test
607     public void kvp() throws JoranException {
608         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "pattern/kvp.xml");
609 
610         String msg = "hello kvp";
611 
612         KeyValuePair kvp1 = new KeyValuePair("k" + diff, "v" + diff);
613         KeyValuePair kvp2 = new KeyValuePair("k" + (diff + 1), "v" + (diff + 1));
614         KeyValuePair kvpNullKey = new KeyValuePair(null, "v" + (diff + 2));
615         KeyValuePair kvpNullValue = new KeyValuePair("k" + (diff + 3), null);
616 
617         logger.atDebug().addKeyValue(kvp1.key, kvp1.value).log(msg);
618         logger.atDebug().addKeyValue(kvp2.key, kvp2.value).log(msg);
619         logger.atDebug().addKeyValue(kvpNullKey.key, kvpNullKey.value).log(msg);
620         logger.atDebug().addKeyValue(kvpNullValue.key, kvpNullValue.value).log(msg);
621 
622         StringListAppender<ILoggingEvent> slAppender = (StringListAppender<ILoggingEvent>) loggerContext
623                 .getLogger("root").getAppender("LIST");
624         assertNotNull(slAppender);
625         assertEquals(4, slAppender.strList.size());
626         assertTrue(slAppender.strList.get(0).contains(kvp1.key + "=\"" + kvp1.value + "\" " + msg));
627         assertTrue(slAppender.strList.get(1).contains(kvp2.key + "=\"" + kvp2.value + "\" " + msg));
628         assertTrue(slAppender.strList.get(2).contains("null=\"" + kvpNullKey.value + "\" " + msg));
629         assertTrue(slAppender.strList.get(3).contains(kvpNullValue.key + "=\"null\" " + msg));
630     }
631 
632 
633     
634     @Test
635     public void inclusionWithVariables() throws JoranException {
636         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "include/topLevel0.xml");
637         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
638         
639         assertEquals(Level.ERROR, root.getLevel());
640     }
641 
642     
643     @Test
644     public void ossFuzz_46697() throws JoranException {
645         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-46697.xml");
646 
647         checker.assertContainsMatch(Status.ERROR, ErrorCodes.EMPTY_MODEL_STACK);
648     }
649 
650     
651     
652     
653     
654     @Test
655     public void ossFuzz_47093() throws JoranException {
656         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47093.xml");
657         assertEquals("a\\t", loggerContext.getProperty("fuzz-47093-a"));
658         assertEquals("a\\\\", loggerContext.getProperty("fuzz-47093-b"));
659     }
660 
661     @Test
662     public void ossFuzz_41117() throws JoranException {
663         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117.xml");
664         checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL);
665         checker.assertErrorCount(2);
666         
667     }
668 
669     @Test
670     public void ossFuzz_41117_bis() throws JoranException {
671         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117-bis.xml");
672         checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL);
673     }
674 
675     @Test
676     public void ossFuzz_41117_bis2() throws JoranException {
677         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47117-bis2.xml");
678         checker.assertContainsMatch(Status.ERROR, ErrorCodes.ROOT_LEVEL_CANNOT_BE_SET_TO_NULL);
679     }
680 
681     @Test
682     public void ossFuzz_47293() throws JoranException {
683         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "ossfuzz/fuzz-47293.xml");
684         checker.assertContainsMatch(Status.ERROR, ErrorCodes.MISSING_IF_EMPTY_MODEL_STACK);
685     }
686 
687 
688     @Test
689     public void dateConverterWithLocale() throws JoranException {
690         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "dateWithLocale.xml");
691         checker.assertContainsMatch(Status.INFO, "Setting zoneId to \"Australia/Perth\"");
692         checker.assertContainsMatch(Status.INFO, "Setting locale to \"en_AU\"");
693         
694     }
695 
696     @Test
697     public void propertyConfiguratorSmoke() throws JoranException {
698         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "propertiesConfigurator/smoke.xml");
699         Logger com_foo_Logger = loggerContext.getLogger("com.toto");
700         
701         assertEquals(Level.WARN, com_foo_Logger.getLevel());
702 
703 
704     }
705 
706     @Test
707     public void consoleCharsetTest() throws JoranException {
708         if (EnvUtil.isJDK21OrHigher()) {
709             configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "consoleCharset.xml");
710             checker.assertContainsMatch(Status.INFO, "About to instantiate property definer of type \\[ch.qos.logback.core.property.ConsoleCharsetPropertyDefiner\\]");
711 
712             Console console = System.console();
713             if(console == null) {
714                 checker.assertContainsMatch(Status.WARN, "System.console\\(\\) returned null. Cannot compute console's charset, returning");
715             } else {
716 
717                 boolean nullCharset =  checker.containsMatch("System.console() returned null charset. Returning \"NULL\" string as defined value.");
718                 boolean foundCharset = checker.containsMatch("Found value '.*' as returned by System.console().");
719 
720             }
721             
722         }
723     }
724 
725     @Test
726     public void levelFromAPropertyTest() throws JoranException {
727 
728 
729         String loggerASysLevelKey = "LOGGER_A_SYS_LEVEL";
730         String loggerNestedSysLevelKey = "LOGGER_NESTED_SYS_LEVEL";
731         System.setProperty(loggerASysLevelKey, "WARN");
732         System.setProperty(loggerNestedSysLevelKey, "ERROR");
733         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "levelFromAProperty.xml");
734 
735 
736         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
737 
738 
739         Logger loggerA = loggerContext.getLogger("A");
740         Logger loggerA_SYS = loggerContext.getLogger("A_SYS");
741 
742         Logger loggerNESTED = loggerContext.getLogger("NESTED");
743 
744         Logger loggerNESTED_SYS = loggerContext.getLogger("NESTED_SYS");
745 
746 
747         assertEquals(Level.TRACE, root.getLevel());
748         assertEquals(Level.WARN, loggerA.getLevel());
749         assertEquals(Level.WARN, loggerA_SYS.getLevel());
750 
751         assertEquals(Level.ERROR, loggerNESTED.getLevel());
752         assertEquals(Level.ERROR, loggerNESTED_SYS.getLevel());
753 
754         checker.assertContainsMatch(Status.INFO, "value \\\"WARN\\\" substituted for \\\"\\$\\{LOGGER_A_LEVEL\\}\\\"");
755 
756         System.clearProperty(loggerASysLevelKey);
757         System.clearProperty(loggerNestedSysLevelKey);
758 
759     }
760 
761     @Test
762     public void exceptionEventFilter() throws JoranException {
763         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "boolex/exceptionEvaluator.xml");
764         Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
765         root.info("deny");
766         root.info("allow", new RuntimeException("test"));
767 
768         ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST");
769         assertNotNull(listAppender);
770         assertEquals(1, listAppender.list.size());
771 
772         ILoggingEvent le = listAppender.list.get(0);
773 
774         assertNotNull(le.getThrowableProxy());
775         assertEquals(RuntimeException.class.getName(), le.getThrowableProxy().getClassName());
776 
777     }
778 
779     @Test
780     public void modelSerialization() throws JoranException, IOException, ClassNotFoundException {
781         String outputPath = OUTPUT_DIR_PREFIX + "minimal_" + diff + MODEL_CONFIG_FILE_EXTENSION;
782 
783         loggerContext.putProperty("targetModelFile", outputPath);
784         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "model/minimal.xml");
785         StatusPrinter.print(loggerContext);
786 
787         FileInputStream fis = new FileInputStream(outputPath);
788         HardenedModelInputStream hmis = new HardenedModelInputStream(fis);
789 
790         Model model = (Model) hmis.readObject();
791 
792         assertNotNull(model);
793         assertTrue(model instanceof ConfigurationModel);
794 
795         ConfigurationModel configurationModel = (ConfigurationModel) model;
796 
797         assertEquals("false", configurationModel.getDebugStr());
798 
799         assertEquals(2, configurationModel.getSubModels().size());
800 
801         SerializeModelModel smm = (SerializeModelModel) configurationModel.getSubModels().get(0);
802         assertEquals("${targetModelFile}", smm.getFile());
803 
804 
805         LoggerModel loggerModel = (LoggerModel) configurationModel.getSubModels().get(1);
806         assertEquals("ModelSerializationTest", loggerModel.getName());
807 
808         
809         
810 
811 
812     }
813 
814 
815     
816 
817 
818 
819 
820 
821 
822 
823 
824 
825 
826 
827 
828 
829 
830 
831 
832 
833 
834 
835 
836 
837 
838 
839 
840 
841 
842 
843 
844 
845 
846 
847 
848 
849 }