1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.joran.action;
15
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21 import java.util.Arrays;
22 import java.util.HashMap;
23 import java.util.Stack;
24 import java.util.function.Supplier;
25
26 import ch.qos.logback.core.model.processor.IncludeModelHandler;
27 import org.junit.jupiter.api.AfterEach;
28 import org.junit.jupiter.api.Assertions;
29 import org.junit.jupiter.api.BeforeEach;
30 import org.junit.jupiter.api.Test;
31 import org.xml.sax.SAXParseException;
32
33 import ch.qos.logback.core.Context;
34 import ch.qos.logback.core.ContextBase;
35 import ch.qos.logback.core.joran.TrivialConfigurator;
36 import ch.qos.logback.core.joran.action.ext.StackAction;
37 import ch.qos.logback.core.joran.spi.ElementSelector;
38 import ch.qos.logback.core.joran.spi.JoranException;
39 import ch.qos.logback.core.model.IncludeModel;
40 import ch.qos.logback.core.model.StackModel;
41 import ch.qos.logback.core.model.TopModel;
42 import ch.qos.logback.core.model.processor.DefaultProcessor;
43 import ch.qos.logback.core.model.processor.NOPModelHandler;
44 import ch.qos.logback.core.model.processor.StackModelHandler;
45 import ch.qos.logback.core.status.Status;
46 import ch.qos.logback.core.testUtil.CoreTestConstants;
47 import ch.qos.logback.core.testUtil.FileTestUtil;
48 import ch.qos.logback.core.testUtil.RandomUtil;
49 import ch.qos.logback.core.status.testUtil.StatusChecker;
50
51 import static ch.qos.logback.core.joran.JoranConstants.CONFIGURATION_TAG;
52 import static ch.qos.logback.core.joran.JoranConstants.INCLUDED_TAG;
53
54
55 public class IncludeModelHandlerTest {
56
57 final static String INCLUDE_KEY = "includeKey";
58 final static String SUB_FILE_KEY = "subFileKey";
59 final static String SECOND_FILE_KEY = "secondFileKey";
60
61 Context context = new ContextBase();
62 StatusChecker statusChecker = new StatusChecker(context);
63 TrivialConfigurator tc;
64
65 static final String INCLUSION_DIR_PREFIX = CoreTestConstants.JORAN_INPUT_PREFIX + "inclusion/";
66
67 static final String TOP_BY_FILE = INCLUSION_DIR_PREFIX + "topByFile.xml";
68
69 static final String TOP_OPTIONAL = INCLUSION_DIR_PREFIX + "topOptional.xml";
70
71 static final String TOP_OPTIONAL_RESOURCE = INCLUSION_DIR_PREFIX + "topOptionalResource.xml";
72
73 static final String INTERMEDIARY_FILE = INCLUSION_DIR_PREFIX + "intermediaryByFile.xml";
74
75 static final String SUB_FILE = INCLUSION_DIR_PREFIX + "subByFile.xml";
76
77 static final String MULTI_INCLUDE_BY_FILE = INCLUSION_DIR_PREFIX + "multiIncludeByFile.xml";
78
79 static final String SECOND_FILE = INCLUSION_DIR_PREFIX + "second.xml";
80
81 static final String TOP_BY_URL = INCLUSION_DIR_PREFIX + "topByUrl.xml";
82
83 static final String TOP_BY_ENTITY = INCLUSION_DIR_PREFIX + "topByEntity.xml";
84
85 static final String INCLUDE_BY_RESOURCE = INCLUSION_DIR_PREFIX + "topByResource.xml";
86
87 static final String INCLUDED_FILE = INCLUSION_DIR_PREFIX + "included.xml";
88 static final String URL_TO_INCLUDE = "file:./" + INCLUDED_FILE;
89
90 static final String INVALID = INCLUSION_DIR_PREFIX + "invalid.xml";
91
92 static final String INCLUDED_AS_RESOURCE = "asResource/joran/inclusion/includedAsResource.xml";
93
94 int diff = RandomUtil.getPositiveInt();
95
96
97 @BeforeEach
98 public void setUp() throws Exception {
99 FileTestUtil.makeTestOutputDir();
100 HashMap<ElementSelector, Supplier<Action>> rulesMap = new HashMap<>();
101 rulesMap.put(new ElementSelector(CONFIGURATION_TAG), () -> new TopElementAction());
102 rulesMap.put(new ElementSelector(CONFIGURATION_TAG+"/include"), () -> new IncludeAction());
103 rulesMap.put(new ElementSelector(CONFIGURATION_TAG+"/stack"), () -> new StackAction());
104
105 tc = new TrivialConfigurator(rulesMap) {
106
107 @Override
108 protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
109 defaultProcessor.addHandler(TopModel.class, NOPModelHandler::makeInstance);
110 defaultProcessor.addHandler(IncludeModel.class, IncludeModelHandler::makeInstance);
111 defaultProcessor.addHandler(StackModel.class, StackModelHandler::makeInstance);
112 }
113
114 public void buildModelInterpretationContext() {
115 super.buildModelInterpretationContext();
116 this.modelInterpretationContext.setConfiguratorSupplier( () -> this.makeAnotherInstance() );
117 }
118 };
119
120 tc.setContext(context);
121 tc.getRuleStore().addPathPathMapping(INCLUDED_TAG, CONFIGURATION_TAG);
122 }
123
124 @AfterEach
125 public void tearDown() throws Exception {
126
127 context = null;
128 System.clearProperty(INCLUDE_KEY);
129 System.clearProperty(SECOND_FILE_KEY);
130 System.clearProperty(SUB_FILE_KEY);
131
132 }
133
134 @Test
135 public void basicFile() throws JoranException {
136 System.setProperty(INCLUDE_KEY, INCLUDED_FILE);
137 tc.doConfigure(TOP_BY_FILE);
138
139 verifyConfig(new String[] { "IA", "IB" });
140 }
141
142 @Test
143 public void optionalFile() throws JoranException {
144 tc.doConfigure(TOP_OPTIONAL);
145 verifyConfig(new String[] { "IA", "IB" });
146
147 }
148
149 @Test
150 public void optionalResource() throws JoranException {
151 tc.doConfigure(TOP_OPTIONAL_RESOURCE);
152 verifyConfig(new String[] { "IA", "IB" });
153
154 Assertions.assertEquals(Status.INFO, statusChecker.getHighestLevel(0));
155 }
156
157 @Test
158 public void basicResource() throws JoranException {
159 System.setProperty(INCLUDE_KEY, INCLUDED_AS_RESOURCE);
160 tc.doConfigure(INCLUDE_BY_RESOURCE);
161 verifyConfig(new String[] { "AR_A", "AR_B" });
162 }
163
164 @Test
165 public void basicURL() throws JoranException {
166 System.setProperty(INCLUDE_KEY, URL_TO_INCLUDE);
167 tc.doConfigure(TOP_BY_URL);
168
169 verifyConfig(new String[] { "IA", "IB" });
170 }
171
172 @Test
173 public void noFileFound() throws JoranException {
174 System.setProperty(INCLUDE_KEY, "toto");
175 tc.doConfigure(TOP_BY_FILE);
176 Assertions.assertEquals(Status.WARN, statusChecker.getHighestLevel(0));
177 }
178
179 @Test
180 public void withCorruptFile() throws JoranException, IOException {
181 String tmpOut = copyToTemp(INVALID);
182 System.setProperty(INCLUDE_KEY, tmpOut);
183 tc.doConfigure(TOP_BY_FILE);
184 Assertions.assertEquals(Status.ERROR, statusChecker.getHighestLevel(0));
185
186 Assertions.assertTrue(statusChecker.containsException(SAXParseException.class));
187
188
189
190 File f = new File(tmpOut);
191 Assertions.assertTrue(f.exists());
192 Assertions.assertTrue(f.delete());
193
194 }
195
196 String copyToTemp(String in) throws IOException {
197 FileInputStream fis = new FileInputStream(in);
198 String out = CoreTestConstants.OUTPUT_DIR_PREFIX + "out" + diff;
199 FileOutputStream fos = new FileOutputStream(out);
200 int b;
201 while ((b = fis.read()) != -1) {
202 fos.write(b);
203 }
204 fis.close();
205 fos.close();
206 return out;
207 }
208
209 @Test
210 public void malformedURL() throws JoranException {
211 String MALFORMED = "htp://logback.qos.ch";
212
213 System.setProperty(INCLUDE_KEY, MALFORMED);
214 tc.doConfigure(TOP_BY_URL);
215 Assertions.assertEquals(Status.ERROR, statusChecker.getHighestLevel(0));
216 Assertions.assertTrue(statusChecker.containsException(MalformedURLException.class));
217 }
218
219 @Test
220 public void unknownURL() throws JoranException {
221 System.setProperty(INCLUDE_KEY, "http://logback2345.qos.ch");
222 tc.doConfigure(TOP_BY_URL);
223 Assertions.assertEquals(Status.WARN, statusChecker.getHighestLevel(0));
224 }
225
226 @Test
227 public void nestedInclude() throws JoranException {
228 System.setProperty(SUB_FILE_KEY, SUB_FILE);
229 System.setProperty(INCLUDE_KEY, INTERMEDIARY_FILE);
230 tc.doConfigure(TOP_BY_FILE);
231 Stack<String> expected = new Stack<String>();
232 expected.push("a");
233 expected.push("b");
234 expected.push("c");
235 @SuppressWarnings({ "unchecked", "rawtypes" })
236 Stack<String> aStack = (Stack) context.getObject(StackModelHandler.STACK_TEST);
237 Assertions.assertEquals(expected, aStack);
238 }
239
240 @Test
241 public void multiInclude() throws JoranException {
242 System.setProperty(INCLUDE_KEY, INCLUDED_FILE);
243 System.setProperty(SECOND_FILE_KEY, SECOND_FILE);
244 tc.doConfigure(MULTI_INCLUDE_BY_FILE);
245 verifyConfig(new String[] { "IA", "IB", "SECOND" });
246 }
247
248
249 @Test
250 public void includeAsEntity() throws JoranException {
251 tc.doConfigure(TOP_BY_ENTITY);
252
253
254
255
256 verifyConfig(null);
257 }
258
259 void verifyConfig(String[] expected) {
260 @SuppressWarnings({ "unchecked", "rawtypes" })
261 Stack<String> aStack = (Stack) context.getObject(StackModelHandler.STACK_TEST);
262
263 if(expected == null) {
264 Assertions.assertNull(aStack);
265 return;
266 }
267
268 Stack<String> witness = new Stack<String>();
269 witness.addAll(Arrays.asList(expected));
270
271 Assertions.assertEquals(witness, aStack);
272 }
273
274 }