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 }