1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2024, 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.core.model.processor;
15  
16  import java.util.HashMap;
17  import java.util.function.Supplier;
18  
19  import ch.qos.logback.core.joran.action.Action;
20  import ch.qos.logback.core.joran.action.DefinePropertyAction;
21  import ch.qos.logback.core.joran.action.TopElementAction;
22  import org.junit.jupiter.api.AfterEach;
23  import org.junit.jupiter.api.BeforeEach;
24  import org.junit.jupiter.api.Disabled;
25  import org.junit.jupiter.api.Test;
26  
27  import ch.qos.logback.core.Context;
28  import ch.qos.logback.core.ContextBase;
29  import ch.qos.logback.core.joran.SimpleConfigurator;
30  import ch.qos.logback.core.joran.spi.ElementSelector;
31  import ch.qos.logback.core.joran.spi.JoranException;
32  import ch.qos.logback.core.model.DefineModel;
33  import ch.qos.logback.core.model.ImplicitModel;
34  import ch.qos.logback.core.model.TopModel;
35  import ch.qos.logback.core.status.Status;
36  import ch.qos.logback.core.testUtil.CoreTestConstants;
37  import ch.qos.logback.core.status.testUtil.StatusChecker;
38  import ch.qos.logback.core.util.StatusPrinter;
39  
40  import static org.junit.jupiter.api.Assertions.assertEquals;
41  import static org.junit.jupiter.api.Assertions.assertNotNull;
42  import static org.junit.jupiter.api.Assertions.assertNull;
43  
44  /**
45   * Test {@link DefinePropertyAction}.
46   * 
47   * @author Aleksey Didik
48   */
49  public class DefinePropertyActionTest {
50  
51      private static final String DEFINE_INPUT_DIR = CoreTestConstants.JORAN_INPUT_PREFIX + "define/";
52      private static final String GOOD_XML = "good.xml";
53      private static final String NONAME_XML = "noname.xml";
54      private static final String NOCLASS_XML = "noclass.xml";
55      private static final String BADCLASS_XML = "badclass.xml";
56  
57      SimpleConfigurator simpleConfigurator;
58      Context context = new ContextBase();
59      StatusChecker checker = new StatusChecker(context);
60  
61      @BeforeEach
62      public void setUp() throws Exception {
63  
64          HashMap<ElementSelector, Supplier<Action>> rulesMap = new HashMap<>();
65          rulesMap.put(new ElementSelector("top"), TopElementAction::new);
66          rulesMap.put(new ElementSelector("top/define"), DefinePropertyAction::new);
67  
68          simpleConfigurator = new SimpleConfigurator(rulesMap) {
69              
70              @Override
71              protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
72                  defaultProcessor.addHandler(TopModel.class, NOPModelHandler::makeInstance);
73                  defaultProcessor.addHandler(DefineModel.class, DefineModelHandler::makeInstance);
74                  defaultProcessor.addHandler(ImplicitModel.class, ImplicitModelHandler::makeInstance);
75              }
76          };
77          simpleConfigurator.setContext(context);
78      }
79  
80      @AfterEach
81      public void tearDown() throws Exception {
82      }
83  
84      @Test
85      public void good() throws JoranException {
86          simpleConfigurator.doConfigure(DEFINE_INPUT_DIR + GOOD_XML);
87          ModelInterpretationContext mic = simpleConfigurator.getModelInterpretationContext();
88          String inContextFoo = mic.getProperty("foo");
89          assertEquals("monster", inContextFoo);
90      }
91  
92      @Test
93      public void noName() throws JoranException {
94          try {
95              simpleConfigurator.doConfigure(DEFINE_INPUT_DIR + NONAME_XML);
96          } finally {
97              StatusPrinter.print(context);
98          }
99          // get from context
100         String inContextFoo = context.getProperty("foo");
101         assertNull(inContextFoo);
102         // check context errors
103 
104         checker.assertContainsMatch(Status.ERROR, "Missing attribute \\[name\\]. See element \\[define\\]");
105     }
106 
107     @Test
108     public void noClass() throws JoranException {
109         simpleConfigurator.doConfigure(DEFINE_INPUT_DIR + NOCLASS_XML);
110         String inContextFoo = context.getProperty("foo");
111 
112         StatusPrinter.print(context);
113         assertNull(inContextFoo);
114         checker.assertContainsMatch(Status.ERROR, "Missing attribute \\[class\\]. See element \\[define\\]");
115     }
116 
117     @Test
118     public void testBadClass() throws JoranException {
119         simpleConfigurator.doConfigure(DEFINE_INPUT_DIR + BADCLASS_XML);
120         // get from context
121         String inContextFoo = context.getProperty("foo");
122         assertNull(inContextFoo);
123         // check context errors
124         checker.assertContainsMatch(Status.ERROR, "Could not create an PropertyDefiner of type");
125     }
126 
127     @Disabled // on certain hosts this test takes 5 seconds to complete
128     @Test
129     public void canonicalHostNameProperty() throws JoranException {
130         String configFileAsStr = DEFINE_INPUT_DIR + "canonicalHostname.xml";
131         simpleConfigurator.doConfigure(configFileAsStr);
132         assertNotNull(context.getProperty("CANONICAL_HOST_NAME"));
133     }
134 
135 }