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