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.core.util;
15  
16  import static org.junit.Assert.assertEquals;
17  import static org.junit.Assert.fail;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import org.junit.Before;
23  import org.junit.Rule;
24  import org.junit.Test;
25  import org.junit.rules.ExpectedException;
26  
27  import ch.qos.logback.core.Context;
28  import ch.qos.logback.core.ContextBase;
29  import ch.qos.logback.core.joran.spi.JoranException;
30  
31  public class OptionHelperTest {
32  
33      @Rule
34      public ExpectedException expectedException = ExpectedException.none();
35  
36      String text = "Testing ${v1} variable substitution ${v2}";
37      String expected = "Testing if variable substitution works";
38      Context context = new ContextBase();
39      Map<String, String> secondaryMap;
40  
41      @Before
42      public void setUp() throws Exception {
43          secondaryMap = new HashMap<String, String>();
44      }
45  
46      @Test
47      public void testLiteral() {
48          String noSubst = "hello world";
49          String result = OptionHelper.substVars(noSubst, context);
50          assertEquals(noSubst, result);
51      }
52  
53      @Test
54      public void testUndefinedValues() {
55          String withUndefinedValues = "${axyz}";
56  
57          String result = OptionHelper.substVars(withUndefinedValues, context);
58          assertEquals("axyz" + OptionHelper._IS_UNDEFINED, result);
59      }
60  
61      @Test
62      public void testSubstVarsVariableNotClosed() {
63          String noSubst = "testing if ${v1 works";
64  
65          try {
66              @SuppressWarnings("unused")
67              String result = OptionHelper.substVars(noSubst, context);
68              fail();
69          } catch (IllegalArgumentException e) {
70              // ok
71          }
72      }
73  
74      @Test
75      public void testSubstVarsContextOnly() {
76          context.putProperty("v1", "if");
77          context.putProperty("v2", "works");
78  
79          String result = OptionHelper.substVars(text, context);
80          assertEquals(expected, result);
81      }
82  
83      @Test
84      public void testSubstVarsSystemProperties() {
85          System.setProperty("v1", "if");
86          System.setProperty("v2", "works");
87  
88          String result = OptionHelper.substVars(text, context);
89          assertEquals(expected, result);
90  
91          System.clearProperty("v1");
92          System.clearProperty("v2");
93      }
94  
95      @Test
96      public void testSubstVarsWithDefault() {
97          context.putProperty("v1", "if");
98          String textWithDefault = "Testing ${v1} variable substitution ${v2:-toto}";
99          String resultWithDefault = "Testing if variable substitution toto";
100 
101         String result = OptionHelper.substVars(textWithDefault, context);
102         assertEquals(resultWithDefault, result);
103     }
104 
105     @Test
106     public void testSubstVarsRecursive() {
107         context.putProperty("v1", "if");
108         context.putProperty("v2", "${v3}");
109         context.putProperty("v3", "works");
110 
111         String result = OptionHelper.substVars(text, context);
112         assertEquals(expected, result);
113     }
114 
115     @Test
116     public void testSubstVarsTwoLevelsDeep() {
117         context.putProperty("v1", "if");
118         context.putProperty("v2", "${v3}");
119         context.putProperty("v3", "${v4}");
120         context.putProperty("v4", "works");
121 
122         String result = OptionHelper.substVars(text, context);
123         assertEquals(expected, result);
124     }
125 
126     @Test
127     public void testSubstVarsTwoLevelsWithDefault() {
128         // Example input taken from LOGBCK-943 bug report
129         context.putProperty("APP_NAME", "LOGBACK");
130         context.putProperty("ARCHIVE_SUFFIX", "archive.log");
131         context.putProperty("LOG_HOME", "${logfilepath.default:-logs}");
132         context.putProperty("ARCHIVE_PATH", "${LOG_HOME}/archive/${APP_NAME}");
133 
134         String result = OptionHelper.substVars("${ARCHIVE_PATH}_trace_${ARCHIVE_SUFFIX}", context);
135         assertEquals("logs/archive/LOGBACK_trace_archive.log", result);
136     }
137 
138     @Test(timeout = 1000)
139     public void stubstVarsShouldNotGoIntoInfiniteLoop() {
140         context.putProperty("v1", "if");
141         context.putProperty("v2", "${v3}");
142         context.putProperty("v3", "${v4}");
143         context.putProperty("v4", "${v2}c");
144 
145         expectedException.expect(Exception.class);
146         OptionHelper.substVars(text, context);
147     }
148 
149     @Test
150     public void nonCircularGraphShouldWork() {
151         context.putProperty("A", "${B} and ${C}");
152         context.putProperty("B", "${B1}");
153         context.putProperty("B1", "B1-value");
154         context.putProperty("C", "${C1} and ${B}");
155         context.putProperty("C1", "C1-value");
156 
157         String result = OptionHelper.substVars("${A}", context);
158         assertEquals("B1-value and C1-value and B1-value", result);
159     }
160 
161     @Test(timeout = 1000)
162     public void detectCircularReferences0() {
163         context.putProperty("A", "${A}");
164 
165         expectedException.expect(IllegalArgumentException.class);
166         expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${A}]");
167         OptionHelper.substVars("${A}", context);
168     }
169 
170     @Test(timeout = 1000)
171     public void detectCircularReferences1() {
172         context.putProperty("A", "${A}a");
173 
174         expectedException.expect(IllegalArgumentException.class);
175         expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${A}]");
176         OptionHelper.substVars("${A}", context);
177     }
178 
179     @Test(timeout = 1000)
180     public void detectCircularReferences2() {
181         context.putProperty("A", "${B}");
182         context.putProperty("B", "${C}");
183         context.putProperty("C", "${A}");
184 
185         expectedException.expect(IllegalArgumentException.class);
186         expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${B} --> ${C} --> ${A}]");
187         OptionHelper.substVars("${A}", context);
188     }
189 
190     @Test
191     public void detectCircularReferencesInDefault() {
192         context.putProperty("A", "${B:-${A}}");
193         expectedException.expect(IllegalArgumentException.class);
194         expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${B} --> ${A}]");
195         OptionHelper.substVars("${A}", context);
196     }
197 
198     @Test(timeout = 1000)
199     public void detectCircularReferences3() {
200         context.putProperty("A", "${B}");
201         context.putProperty("B", "${C}");
202         context.putProperty("C", "${A}");
203 
204         expectedException.expect(IllegalArgumentException.class);
205         expectedException.expectMessage("Circular variable reference detected while parsing input [${B} --> ${C} --> ${A} --> ${B}]");
206         OptionHelper.substVars("${B} ", context);
207     }
208 
209     @Test(timeout = 1000)
210     public void detectCircularReferences4() {
211         context.putProperty("A", "${B}");
212         context.putProperty("B", "${C}");
213         context.putProperty("C", "${A}");
214 
215         expectedException.expect(IllegalArgumentException.class);
216         expectedException.expectMessage("Circular variable reference detected while parsing input [${C} --> ${A} --> ${B} --> ${C}]");
217         OptionHelper.substVars("${C} and ${A}", context);
218     }
219 
220     @Test
221     public void detectCircularReferences5() {
222         context.putProperty("A", "${B} and ${C}");
223         context.putProperty("B", "${B1}");
224         context.putProperty("B1", "B1-value");
225         context.putProperty("C", "${C1}");
226         context.putProperty("C1", "here's the loop: ${A}");
227 
228         expectedException.expect(IllegalArgumentException.class);
229         expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${C} --> ${C1} --> ${A}]");
230         String result = OptionHelper.substVars("${A}", context);
231         System.err.println(result);
232     }
233 
234     @Test
235     public void defaultValueReferencingAVariable() {
236         context.putProperty("v1", "k1");
237         String result = OptionHelper.substVars("${undef:-${v1}}", context);
238         assertEquals("k1", result);
239     }
240 
241     @Test
242     public void jackrabbit_standalone() {
243         String r = OptionHelper.substVars("${jackrabbit.log:-${repo:-jackrabbit}/log/jackrabbit.log}", context);
244         assertEquals("jackrabbit/log/jackrabbit.log", r);
245     }
246 
247     @Test
248     public void doesNotThrowNullPointerExceptionForEmptyVariable() throws JoranException {
249         context.putProperty("var", "");
250         OptionHelper.substVars("${var}", context);
251     }
252 
253     @Test
254     public void trailingColon_LOGBACK_1140() {
255         String prefix = "c:";
256         String suffix = "/tmp";
257         context.putProperty("var", prefix);
258         String r = OptionHelper.substVars("${var}" + suffix, context);
259         assertEquals(prefix + suffix, r);
260     }
261 
262     @Test
263     public void curlyBraces_LOGBACK_1101() {
264         {
265             String input = "foo{bar}";
266             String r = OptionHelper.substVars(input, context);
267             assertEquals(input, r);
268         }
269         {
270             String input = "{foo{\"bar\"}}";
271             String r = OptionHelper.substVars(input, context);
272             assertEquals(input, r);
273         }
274         {
275             String input = "a:{y}";
276             String r = OptionHelper.substVars(input, context);
277             assertEquals(input, r);
278         }
279         {
280             String input = "{world:{yay}}";
281             String r = OptionHelper.substVars(input, context);
282             assertEquals(input, r);
283         }
284         {
285             String input = "{hello:{world:yay}}";
286             String r = OptionHelper.substVars(input, context);
287             assertEquals(input, r);
288         }
289         {
290             String input = "{\"hello\":{\"world\":\"yay\"}}";
291             String r = OptionHelper.substVars(input, context);
292             assertEquals(input, r);
293         }
294     }
295 }