001 /* 002 * Copyright 1999-2001,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.apache.commons.latka; 018 019 // java imports 020 import java.io.IOException; 021 import java.io.PrintWriter; 022 import java.io.StringWriter; 023 // latka imports 024 import org.apache.commons.latka.event.LatkaEventListener; 025 import org.apache.commons.latka.event.ReportMessageEvent; 026 import org.apache.commons.latka.event.RequestErrorEvent; 027 import org.apache.commons.latka.event.RequestEvent; 028 import org.apache.commons.latka.event.RequestFailedEvent; 029 import org.apache.commons.latka.event.SuiteEvent; 030 import org.apache.commons.latka.http.Request; 031 // dom4j imports 032 import org.dom4j.Document; 033 import org.dom4j.DocumentFactory; 034 import org.dom4j.Element; 035 import org.dom4j.io.OutputFormat; 036 import org.dom4j.io.XMLWriter; 037 038 /** 039 * This LatkaEventListener will generate an XML report 040 * of all tests run during an Latka XML suite. XMLReporter 041 * instances are NOT reusable for multiple invocations 042 * of the {@link 043 * org.apache.commons.latka.Latka#runTests(org.apache.commons.latka.Suite, 044 * org.apache.commons.latka.event.LatkaEventInfo) 045 * Latka#runTests(Suite, LatkaEventInfo)} method. 046 * 047 * @author Morgan Delagrange 048 * @author dIon Gillard 049 * @version $Id: XMLReporter.java 155424 2005-02-26 13:09:29Z dirkv $ 050 */ 051 public class XMLReporter extends AbstractReporter implements LatkaEventListener { 052 /** dom4j document produced as output */ 053 protected Document _doc = null; 054 /** top level element of dom4j document, a <report> element*/ 055 protected Element _rootElement = null; 056 /** used for output as tests run */ 057 protected PrintWriter _printWriter = new PrintWriter(System.out); 058 059 protected boolean _didSuiteSucceed = true; 060 061 protected DocumentFactory _factory = new DocumentFactory(); 062 063 /** 064 * Create an XML Reporter, initialising document property, as a new empty 065 * report with an unsuccessful suite 066 */ 067 public XMLReporter() { 068 _rootElement = _factory.createElement("report"); 069 //defaults to false, until a SuiteSuccess event occurs 070 _doc = _factory.createDocument(_rootElement); 071 _rootElement.addAttribute("suiteSuccess", "false"); 072 } 073 074 /** 075 * Returns the XML Document produced by this listener 076 * 077 * @return dom4j representation of the test report 078 */ 079 public Document getDocument() { 080 return _doc; 081 } 082 083 /** 084 * Returns the test report converted from dom4j to a 085 * text string. 086 * 087 * @return the test report as an XML string 088 * @throws IOException if the XML formatter cannot convert the dom4j object 089 * to text 090 */ 091 public String getDocumentAsString() throws IOException { 092 // get the xml string from the listener 093 StringWriter writer = new StringWriter(); 094 XMLWriter outputter = new XMLWriter(writer, new OutputFormat(" ", true)); 095 096 outputter.write(getDocument()); 097 098 String xmlDocument = writer.toString(); 099 100 return xmlDocument; 101 } 102 103 /** 104 * @see AbstractReporter#requestError(RequestEvent) 105 * @param event the event detailing the request in error 106 */ 107 public void requestError(RequestEvent event) { 108 _didSuiteSucceed = false; 109 110 _printWriter.print("E"); 111 _printWriter.flush(); 112 113 RequestErrorEvent errorEvent = (RequestErrorEvent) event; 114 // <root><request><requestError><label>errortext</label> 115 // </requestError></request></root> 116 Element label = _factory.createElement("label") 117 .addText(errorEvent.getError().toString()); 118 Element requestError = _factory.createElement("requestError"); 119 requestError.add(label); 120 121 Element requestElement = createRequestElement(event); 122 requestElement.add(requestError); 123 _rootElement.add(requestElement); 124 125 } 126 127 /** 128 * @see AbstractReporter#requestSucceeded(RequestEvent) 129 * @param event the event detailing the request that succeeded 130 */ 131 public void requestSucceeded(RequestEvent event) { 132 133 _printWriter.print("."); 134 _printWriter.flush(); 135 136 Element requestElement = createRequestElement(event); 137 requestElement.add(_factory.createElement("requestSuccess")); 138 _rootElement.add(requestElement); 139 } 140 141 /** 142 * @see AbstractReporter#requestFailed(RequestEvent) 143 * @param event the event detailing the request that failed 144 */ 145 public void requestFailed(RequestEvent event) { 146 _didSuiteSucceed = false; 147 148 _printWriter.print("F"); 149 _printWriter.flush(); 150 151 RequestFailedEvent failedEvent = (RequestFailedEvent) event; 152 153 // <root><request><requestFailure responseId="xxx"><label>XXX</label> 154 // </requestFailure></request></root> 155 Element label = _factory.createElement("label") 156 .addText(failedEvent.getValidationException() 157 .getMessage() 158 .toString()); 159 Element requestFailure = _factory.createElement("requestFailure") 160 .addAttribute("responseId", 161 event.getResponse().toString() 162 ); 163 requestFailure.add(label); 164 165 Element requestElement = createRequestElement(event); 166 requestElement.add(requestFailure); 167 _rootElement.add(requestElement); 168 } 169 170 /** 171 * @see AbstractReporter#requestSkipped(RequestEvent) 172 * @param event the event detailing the request that was skipped 173 */ 174 public void requestSkipped(RequestEvent event) { 175 _didSuiteSucceed = false; 176 177 _printWriter.print("S"); 178 _printWriter.flush(); 179 180 Request request = event.getRequest(); 181 // <root><request><requestSkipped/></request></root> 182 Element requestElement = createRequestElement(event); 183 requestElement.add(_factory.createElement("requestSkipped")); 184 _rootElement.add(requestElement); 185 186 } 187 188 /** 189 * Add the {@link ReportMessageEvent#getMessage() message} of the provided 190 * event to the XML document as a <reportMessage> element with text 191 * 192 * @param event a {@link ReportMessageEvent} 193 */ 194 public void reportMessage(ReportMessageEvent event) { 195 Element messageElement = _factory.createElement("reportMessage") 196 .addAttribute("message", event.getMessage()); 197 _rootElement.add(messageElement); 198 } 199 200 /** 201 * @see AbstractReporter#suiteCompleted(SuiteEvent) 202 * @param event the event detailing the completing Suite 203 */ 204 public void suiteCompleted(SuiteEvent event) { 205 _rootElement.addAttribute("suiteSuccess", 206 String.valueOf(_didSuiteSucceed)); 207 } 208 209 /** 210 * Utility method that converts a RequestEvent object to its 211 * corresponding element in the dom4j object. 212 * 213 * @param event the request event sent to the listener 214 * @return the dom4j Element equivalent 215 */ 216 protected Element createRequestElement(RequestEvent event) { 217 // the request object 218 Request request = event.getRequest(); 219 220 Element requestElement = _factory.createElement("request") 221 .addAttribute("requestTime", 222 String.valueOf(request.getRequestTiming())) 223 .addAttribute("url", request.getURL().toString()); 224 225 String label = request.getLabel(); 226 if (label != null) { 227 requestElement.addAttribute("label", label); 228 } 229 230 return requestElement; 231 } 232 233 /** 234 * During the execution, any diagnostic ouput will be sent 235 * to the stream designated here. If no PrintWriter 236 * is set, output will be sent to standard out. 237 * 238 * @param writer PrintWriter that will receive output generated during 239 * the test 240 */ 241 public void setPrintWriter(PrintWriter writer) { 242 _printWriter = writer; 243 } 244 245 }