1 /*
2 * Copyright 1999-2001,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.latka;
18
19 // java imports
20 import java.io.IOException;
21 import java.io.PrintWriter;
22 import java.io.StringWriter;
23 // latka imports
24 import org.apache.commons.latka.event.LatkaEventListener;
25 import org.apache.commons.latka.event.ReportMessageEvent;
26 import org.apache.commons.latka.event.RequestErrorEvent;
27 import org.apache.commons.latka.event.RequestEvent;
28 import org.apache.commons.latka.event.RequestFailedEvent;
29 import org.apache.commons.latka.event.SuiteEvent;
30 import org.apache.commons.latka.http.Request;
31 // dom4j imports
32 import org.dom4j.Document;
33 import org.dom4j.DocumentFactory;
34 import org.dom4j.Element;
35 import org.dom4j.io.OutputFormat;
36 import org.dom4j.io.XMLWriter;
37
38 /**
39 * This LatkaEventListener will generate an XML report
40 * of all tests run during an Latka XML suite. XMLReporter
41 * instances are NOT reusable for multiple invocations
42 * of the {@link
43 * org.apache.commons.latka.Latka#runTests(org.apache.commons.latka.Suite,
44 * org.apache.commons.latka.event.LatkaEventInfo)
45 * Latka#runTests(Suite, LatkaEventInfo)} method.
46 *
47 * @author Morgan Delagrange
48 * @author dIon Gillard
49 * @version $Id: XMLReporter.java 155424 2005-02-26 13:09:29Z dirkv $
50 */
51 public class XMLReporter extends AbstractReporter implements LatkaEventListener {
52 /** dom4j document produced as output */
53 protected Document _doc = null;
54 /** top level element of dom4j document, a <report> element*/
55 protected Element _rootElement = null;
56 /** used for output as tests run */
57 protected PrintWriter _printWriter = new PrintWriter(System.out);
58
59 protected boolean _didSuiteSucceed = true;
60
61 protected DocumentFactory _factory = new DocumentFactory();
62
63 /**
64 * Create an XML Reporter, initialising document property, as a new empty
65 * report with an unsuccessful suite
66 */
67 public XMLReporter() {
68 _rootElement = _factory.createElement("report");
69 //defaults to false, until a SuiteSuccess event occurs
70 _doc = _factory.createDocument(_rootElement);
71 _rootElement.addAttribute("suiteSuccess", "false");
72 }
73
74 /**
75 * Returns the XML Document produced by this listener
76 *
77 * @return dom4j representation of the test report
78 */
79 public Document getDocument() {
80 return _doc;
81 }
82
83 /**
84 * Returns the test report converted from dom4j to a
85 * text string.
86 *
87 * @return the test report as an XML string
88 * @throws IOException if the XML formatter cannot convert the dom4j object
89 * to text
90 */
91 public String getDocumentAsString() throws IOException {
92 // get the xml string from the listener
93 StringWriter writer = new StringWriter();
94 XMLWriter outputter = new XMLWriter(writer, new OutputFormat(" ", true));
95
96 outputter.write(getDocument());
97
98 String xmlDocument = writer.toString();
99
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 }