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.html;
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.assertTrue;
20  
21  import java.io.ByteArrayInputStream;
22  import java.util.List;
23  
24  import org.dom4j.Document;
25  import org.dom4j.Element;
26  import org.dom4j.io.SAXReader;
27  import org.junit.After;
28  import org.junit.Before;
29  import org.junit.Ignore;
30  import org.junit.Test;
31  import org.xml.sax.EntityResolver;
32  
33  import ch.qos.logback.classic.ClassicTestConstants;
34  import ch.qos.logback.classic.Level;
35  import ch.qos.logback.classic.Logger;
36  import ch.qos.logback.classic.LoggerContext;
37  import ch.qos.logback.classic.joran.JoranConfigurator;
38  import ch.qos.logback.classic.spi.DummyThrowableProxy;
39  import ch.qos.logback.classic.spi.ILoggingEvent;
40  import ch.qos.logback.classic.spi.LoggingEvent;
41  import ch.qos.logback.classic.spi.StackTraceElementProxy;
42  import ch.qos.logback.classic.spi.ThrowableProxy;
43  import ch.qos.logback.core.CoreConstants;
44  import ch.qos.logback.core.joran.spi.JoranException;
45  import ch.qos.logback.core.testUtil.StringListAppender;
46  import ch.qos.logback.core.util.StatusPrinter;
47  
48  public class HTMLLayoutTest {
49  
50      LoggerContext lc;
51      Logger root;
52      HTMLLayout layout;
53  
54      @Before
55      public void setUp() throws Exception {
56          lc = new LoggerContext();
57          lc.setName("default");
58  
59          layout = new HTMLLayout();
60          layout.setThrowableRenderer(new DefaultThrowableRenderer());
61          layout.setContext(lc);
62          layout.setPattern("%level%thread%msg");
63          layout.start();
64  
65          root = lc.getLogger(Logger.ROOT_LOGGER_NAME);
66  
67      }
68  
69      @After
70      public void tearDown() throws Exception {
71          lc = null;
72          layout = null;
73      }
74  
75      @Test
76      public void testHeader() throws Exception {
77          String header = layout.getFileHeader();
78          // System.out.println(header);
79  
80          Document doc = parseOutput(header + "</body></html>");
81          Element rootElement = doc.getRootElement();
82          assertNotNull(rootElement.element("body"));
83      }
84  
85      @Test
86      public void testPresentationHeader() throws Exception {
87          String header = layout.getFileHeader();
88          String presentationHeader = layout.getPresentationHeader();
89          header = header + presentationHeader;
90          // System.out.println(header);
91  
92          Document doc = parseOutput(header + "</table></body></html>");
93          Element rootElement = doc.getRootElement();
94          Element bodyElement = rootElement.element("body");
95          Element tableElement = bodyElement.element("table");
96          Element trElement = tableElement.element("tr");
97          List<Element> elementList = trElement.elements();
98          assertEquals("Level", elementList.get(0).getText());
99          assertEquals("Thread", elementList.get(1).getText());
100         assertEquals("Message", elementList.get(2).getText());
101     }
102 
103     @Test
104     public void testAppendThrowable() throws Exception {
105         StringBuilder buf = new StringBuilder();
106         DummyThrowableProxy tp = new DummyThrowableProxy();
107         tp.setClassName("test1");
108         tp.setMessage("msg1");
109 
110         StackTraceElement ste1 = new StackTraceElement("c1", "m1", "f1", 1);
111         StackTraceElement ste2 = new StackTraceElement("c2", "m2", "f2", 2);
112 
113         StackTraceElementProxy[] stepArray = { new StackTraceElementProxy(ste1), new StackTraceElementProxy(ste2) };
114         tp.setStackTraceElementProxyArray(stepArray);
115         DefaultThrowableRenderer renderer = (DefaultThrowableRenderer) layout.getThrowableRenderer();
116 
117         renderer.render(buf, tp);
118         System.out.println(buf.toString());
119         String[] result = buf.toString().split(CoreConstants.LINE_SEPARATOR);
120         System.out.println(result[0]);
121         assertEquals("test1: msg1", result[0]);
122         assertEquals(DefaultThrowableRenderer.TRACE_PREFIX + "at c1.m1(f1:1)", result[1]);
123     }
124 
125     @Test
126     public void testDoLayout() throws Exception {
127         ILoggingEvent le = createLoggingEvent();
128 
129         String result = layout.getFileHeader();
130         result += layout.getPresentationHeader();
131         result += layout.doLayout(le);
132         result += layout.getPresentationFooter();
133         result += layout.getFileFooter();
134 
135         Document doc = parseOutput(result);
136         Element rootElement = doc.getRootElement();
137         rootElement.toString();
138 
139         // the rest of this test is very dependent of the output generated
140         // by HTMLLayout. Given that the XML parser already verifies
141         // that the result conforms to xhtml-strict, we may want to
142         // skip the assertions below. However, the assertions below are another
143         // *independent* way to check the output format.
144 
145         // head, body
146         assertEquals(2, rootElement.elements().size());
147         Element bodyElement = (Element) rootElement.elements().get(1);
148         Element tableElement = (Element) bodyElement.elements().get(3);
149         assertEquals("table", tableElement.getName());
150         Element trElement = (Element) tableElement.elements().get(1);
151         {
152             Element tdElement = (Element) trElement.elements().get(0);
153             assertEquals("DEBUG", tdElement.getText());
154         }
155         {
156             Element tdElement = (Element) trElement.elements().get(1);
157             String regex = ClassicTestConstants.NAKED_MAIN_REGEX;
158             System.out.println(tdElement.getText());
159             assertTrue(tdElement.getText().matches(regex));
160         }
161         {
162             Element tdElement = (Element) trElement.elements().get(2);
163             assertEquals("test message", tdElement.getText());
164         }
165     }
166 
167     @Test
168     public void layoutWithException() throws Exception {
169         layout.setPattern("%level %thread %msg %ex");
170         LoggingEvent le = createLoggingEvent();
171         le.setThrowableProxy(new ThrowableProxy(new Exception("test Exception")));
172         String result = layout.doLayout(le);
173 
174         String stringToParse = layout.getFileHeader();
175         stringToParse = stringToParse + layout.getPresentationHeader();
176         stringToParse += result;
177         stringToParse += "</table></body></html>";
178 
179         // System.out.println(stringToParse);
180 
181         Document doc = parseOutput(stringToParse);
182         Element rootElement = doc.getRootElement();
183         Element bodyElement = rootElement.element("body");
184         Element tableElement = bodyElement.element("table");
185         List<Element> trElementList = tableElement.elements();
186         Element exceptionRowElement = trElementList.get(2);
187         Element exceptionElement = exceptionRowElement.element("td");
188 
189         assertEquals(3, tableElement.elements().size());
190         assertTrue(exceptionElement.getText().contains("java.lang.Exception: test Exception"));
191     }
192 
193     @Test
194     @Ignore
195     public void rawLimit() throws Exception {
196         StringBuilder sb = new StringBuilder();
197         String header = layout.getFileHeader();
198         assertTrue(header.startsWith("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"));
199         sb.append(header);
200         sb.append(layout.getPresentationHeader());
201         for (int i = 0; i < CoreConstants.TABLE_ROW_LIMIT * 3; i++) {
202             sb.append(layout.doLayout(new LoggingEvent(this.getClass().getName(), root, Level.DEBUG, "test message" + i, null, null)));
203         }
204         sb.append(layout.getPresentationFooter());
205         sb.append(layout.getFileFooter());
206         // check that the output adheres to xhtml-strict.dtd
207         parseOutput(sb.toString());
208     }
209 
210     private LoggingEvent createLoggingEvent() {
211         return new LoggingEvent(this.getClass().getName(), root, Level.DEBUG, "test message", null, null);
212     }
213 
214     Document parseOutput(String output) throws Exception {
215         EntityResolver resolver = new XHTMLEntityResolver();
216         SAXReader reader = new SAXReader();
217         reader.setValidation(true);
218         reader.setEntityResolver(resolver);
219         return reader.read(new ByteArrayInputStream(output.getBytes()));
220     }
221 
222     void configure(String file) throws JoranException {
223         JoranConfigurator jc = new JoranConfigurator();
224         jc.setContext(lc);
225         jc.doConfigure(file);
226     }
227 
228     @Test
229     public void testConversionRuleSupportInHtmlLayout() throws JoranException {
230         configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "conversionRule/htmlLayout0.xml");
231 
232         root.getAppender("LIST");
233         String msg = "Simon says";
234         root.debug(msg);
235         StringListAppender<ILoggingEvent> sla = (StringListAppender<ILoggingEvent>) root.getAppender("LIST");
236         assertNotNull(sla);
237         StatusPrinter.print(lc);
238         assertEquals(1, sla.strList.size());
239         assertFalse(sla.strList.get(0).contains("PARSER_ERROR"));
240     }
241 }