/* * Copyright (c) 2004, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.service.junit.client; import junit.framework.*; import java.util.*; import java.net.*; import java.io.*; import org.w3c.dom.*; import javax.xml.parsers.*; import java.lang.reflect.*; public class JUnitClient extends TestSuite { static final String TAG_JUNIT = "junit"; static final String TAG_TESTCASE = "testcase"; static final String TAG_TESTRESULT = "testresult"; static final String TAG_FAILURES = "failures"; static final String TAG_ERRORS = "errors"; static final String TAG_FAILURE = "failure"; static final String TAG_TRACE = "trace"; static final String TAG_CASE = "case"; static final String TAG_SUITE = "suite"; static final String ATTR_EXCEPTIONMESSAGE = "exceptionMessage"; static final String ATTR_FAILEDTESTCASENAME = "failedTestCaseName"; static final String ATTR_FAILEDTESTCASECLASS = "failedTestCaseClass"; static final String ATTR_NAME = "name"; static final String ATTR_CLASS = "class"; URL targetURL = null; JUnitClient() { } /** * Construct a test suite from the URL specified by the * system property suite.url * *

* If loading fails in any way, wrap this in a failed test * case, added to the suite. *

*/ public static Test suite() throws Exception { URL url = new URL(System.getProperty("suite.url")); JUnitClient suite = new JUnitClient(); suite.load(url); return suite; } /** * Read tests and results from the specified URL. */ public void load(URL url) { this.targetURL = url; InputStream in = null; try { in = targetURL.openStream(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(in); parseDoc(doc.getDocumentElement()); } catch (Exception e) { // If document loading failed by any reason, present this // as a failed test case. final StringWriter w = new StringWriter(); e.printStackTrace(new PrintWriter(w)); // This test will always fail with a trace from the // caught load exception. Test test = new TestCase(e.getClass().getName()) { public void runTest() { throw new RemoteAssertionFailedError(getName(), "targetURL=" + targetURL + "\n" + w.toString()); } }; // ...a nice way of logging failures addTest(test); } finally { try { in.close(); } catch (Exception ignored) { } } } void parseDoc(Element el) { if(TAG_JUNIT.equals(el.getTagName())) { parseJUnit(el); } else { NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_JUNIT.equals(childEl.getTagName())) { parseJUnit(childEl); } } } } } void parseJUnit(Element el) { assertTagName(el, TAG_JUNIT); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_TESTCASE.equals(childEl.getTagName())) { parseTestCase(childEl); } } } } void parseTestCase(Element el) { assertTagName(el, TAG_TESTCASE); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_TESTRESULT.equals(childEl.getTagName())) { parseTestResult(childEl); } if(TAG_SUITE.equals(childEl.getTagName())) { parseSuite(childEl); } } } } void parseSuite(Element el) { assertTagName(el, TAG_SUITE); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_SUITE.equals(childEl.getTagName())) { parseSuite(childEl); } if(TAG_CASE.equals(childEl.getTagName())) { RemoteTest test = new RemoteTest(childEl.getAttribute(ATTR_CLASS), childEl.getAttribute(ATTR_NAME), "", ""); addTest(test); } } } } void parseTestResult(Element el) { assertTagName(el, TAG_TESTRESULT); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_FAILURES.equals(childEl.getTagName())) { parseFailures(childEl); } else if(TAG_ERRORS.equals(childEl.getTagName())) { parseErrors(childEl); } } } } void parseFailures(Element el) { assertTagName(el, TAG_FAILURES); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_FAILURE.equals(childEl.getTagName())) { parseFailure(childEl, false); } } } } void parseErrors(Element el) { assertTagName(el, TAG_ERRORS); NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_FAILURE.equals(childEl.getTagName())) { parseFailure(childEl, true); } } } } void parseFailure(Element el, boolean bError) { assertTagName(el, TAG_FAILURE); String exceptionMessage = el.getAttribute(ATTR_EXCEPTIONMESSAGE); String failedTestCaseName = el.getAttribute(ATTR_FAILEDTESTCASENAME); String failedTestCaseClass = el.getAttribute(ATTR_FAILEDTESTCASECLASS); String trace = ""; NodeList nl = el.getChildNodes(); for(int i = 0; i < nl.getLength(); i++) { Node child = nl.item(i); if(child instanceof Element) { Element childEl = (Element)child; if(TAG_TRACE.equals(childEl.getTagName())) { Text text = (Text)childEl.getFirstChild(); trace = text.getData(); } } } RemoteTest test = null; for(int i = 0; i < testCount(); i++) { RemoteTest rt = (RemoteTest)testAt(i); if(rt.name.equals(failedTestCaseName) && rt.className.equals(failedTestCaseClass)) { test = rt; } } if(test == null) { throw new IllegalArgumentException("Unknown test " + failedTestCaseClass + ", " + failedTestCaseName); } test.exceptionMessage = exceptionMessage; test.trace = trace; test.bFailure = !bError; test.bError = bError; if(bError) { test.error = new RemoteError(exceptionMessage, trace); } else { test.error = new RemoteAssertionFailedError(exceptionMessage, trace); } } static void assertTagName(Element el, String name) { if(!name.equals(el.getTagName())) { throw new IllegalArgumentException("expected '" + name + "', found " + " '" + el.getTagName() + "'"); } } static int getInt(Element el, String attr, int def) { String s = el.getAttribute(attr); int v = def; if(s != null) { try { v = Integer.parseInt(s); } catch (Exception e) { } } return v; } public String toString() { return "JUnitClient[" + targetURL + "]"; } } class RemoteTest extends TestCase { String name; String className; String exceptionMessage; String trace; boolean bFailure = false; boolean bError = false; Error error = null; RemoteTest(String className, String name, String exceptionMessage, String trace) { super(name); this.name = name; this.className = className; this.exceptionMessage = exceptionMessage; this.trace = trace; } public String toString() { return name + "(" + className + ")"; } public int hashCode() { return toString().hashCode(); } public boolean equals(Object other) { if(other == null || !(other instanceof RemoteTest)) { return false; } return toString().equals(other.toString()); } public int countTestCases() { return 1; } public void runTest() { if(bFailure || bError) { throw error; } } } class RemoteAssertionFailedError extends AssertionFailedError { String trace; RemoteAssertionFailedError(String name, String trace) { super(name); this.trace = trace; } public void printStackTrace(PrintStream s) { s.print(trace); } public void printStackTrace(PrintWriter s) { s.print(trace); } } class RemoteError extends Error { String trace; RemoteError(String name, String trace) { super(name); this.trace = trace; } public void printStackTrace(PrintStream s) { s.print(trace); } public void printStackTrace(PrintWriter s) { s.print(trace); } }