Skip to content

Commit

Permalink
Added JUnit report generator.
Browse files Browse the repository at this point in the history
A custom JUnit test runner has been added to capture test results
and generate XML reports.

Ticket #36
  • Loading branch information
edewata committed Dec 5, 2011
1 parent d325f2d commit 343a8af
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 6 deletions.
11 changes: 10 additions & 1 deletion pki/base/common/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ set(pki-common-test_SRCS
com/netscape/cmscore/request/RequestTest.java
com/netscape/cmscore/test/CMSBaseTestCase.java
com/netscape/cmscore/test/TestHelper.java
com/netscape/test/TestListener.java
com/netscape/test/TestRunner.java
)

set(CMAKE_JAVA_INCLUDE_PATH
Expand All @@ -64,6 +66,7 @@ set(CMAKE_JAVA_TARGET_VERSION ${APPLICATION_VERSION})

# build test jar file
# TODO: create CMake function to compile without building jar file
# TODO: build test only when the test is invoked
set(CMAKE_JAR_CLASSES_PREFIX com/netscape)
add_jar(pki-common-test ${pki-common-test_SRCS})
add_dependencies(pki-common-test
Expand All @@ -72,11 +75,15 @@ add_dependencies(pki-common-test
)

# create test target
# do not include xalan and xerces in class path
# TODO: create CMake function to find all JUnit test classes
add_junit_test(test-pki-common
CLASSPATH
${pki-common-test_JAR_FILE}
${CMAKE_JAVA_INCLUDE_PATH}
${PKI_NSUTIL_JAR} ${PKI_CMSUTIL_JAR}
${PKI_CERTSRV_JAR} ${PKI_CMS_JAR} ${PKI_CMSCORE_JAR} ${PKI_CMSBUNDLE_JAR}
${LDAPJDK_JAR} ${SERVLET_JAR} ${VELOCITY_JAR}
${JSS_JAR} ${OSUTIL_JAR} ${SYMKEY_JAR} ${JUNIT_JAR}
TESTS
com.netscape.certsrv.authentication.AuthTokenTest
com.netscape.certsrv.request.AgentApprovalsTest
Expand All @@ -87,6 +94,8 @@ add_junit_test(test-pki-common
com.netscape.cmscore.request.RequestQueueTest
com.netscape.cmscore.request.RequestRecordTest
com.netscape.cmscore.request.RequestTest
REPORTS_DIR
reports
)

# include test into the main test
Expand Down
233 changes: 233 additions & 0 deletions pki/base/common/test/com/netscape/test/TestListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package com.netscape.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintStream;
import java.net.InetAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class TestListener extends RunListener {

DateFormat dateFormat;

DocumentBuilderFactory docBuilderFactory;
DocumentBuilder docBuilder;
Document document;

TransformerFactory transFactory;
Transformer trans;

String reportsDir;

Element testSuiteElement;
long testSuiteStartTime;

Element testCaseElement;
long testCaseStartTime;

String currentTestSuiteName;

long testCount;
long successCount;
long failureCount;

PrintStream stdOut;
PrintStream stdErr;

ByteArrayOutputStream out;
ByteArrayOutputStream err;

public TestListener() throws Exception {

dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilder = docBuilderFactory.newDocumentBuilder();

transFactory = TransformerFactory.newInstance();
trans = transFactory.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");

reportsDir = System.getProperty("junit.reports.dir");
}

public void testRunFinished(Result result) throws Exception {
if (currentTestSuiteName != null) {
finishTestSuite(); // finish last suite
}
}

public void testStarted(Description description) throws Exception {

String testSuiteName = description.getClassName();

if (currentTestSuiteName == null) {
startTestSuite(testSuiteName); // start first suite

} else if (!currentTestSuiteName.equals(testSuiteName)) {
finishTestSuite(); // finish old suite
startTestSuite(testSuiteName); // start new suite
}

currentTestSuiteName = testSuiteName;

startTestCase(description);
}

public void testFinished(Description description) throws Exception {
finishTestCase();
recordTestCaseSuccess();
}

public void testFailure(Failure failure) throws Exception {
finishTestCase();
recordTestCaseFailure(failure);
}

public void startTestSuite(String testSuiteName) throws Exception {

testSuiteStartTime = System.currentTimeMillis();

document = docBuilder.newDocument();

// test suite
testSuiteElement = document.createElement("testsuite");
document.appendChild(testSuiteElement);

testSuiteElement.setAttribute("name", testSuiteName);
testSuiteElement.setAttribute("timestamp",
dateFormat.format(new Date(testSuiteStartTime)));
testSuiteElement.setAttribute("hostname",
InetAddress.getLocalHost().getHostName());

// system properties
Element propertiesElement = document.createElement("properties");
testSuiteElement.appendChild(propertiesElement);

for (String name : System.getProperties().stringPropertyNames()) {
Element propertyElement = document.createElement("property");
propertyElement.setAttribute("name", name);
propertyElement.setAttribute("value", System.getProperty(name));
propertiesElement.appendChild(propertyElement);
}

// reset counters
testCount = 0;
successCount = 0;
failureCount = 0;

// redirect outputs
stdOut = System.out;
out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out, true));

stdErr = System.err;
err = new ByteArrayOutputStream();
System.setErr(new PrintStream(err, true));
}

public void finishTestSuite() throws Exception {

double time = (System.currentTimeMillis() - testSuiteStartTime) / 1000.0;
testSuiteElement.setAttribute("time", "" + time);

// save counters
long errorCount = testCount - successCount - failureCount;

testSuiteElement.setAttribute("tests", "" + testCount);
testSuiteElement.setAttribute("failures", "" + failureCount);
testSuiteElement.setAttribute("errors", "" + errorCount);

// save outputs
System.setOut(stdOut);
System.setErr(stdErr);

Element systemOutElement = document.createElement("system-out");
testSuiteElement.appendChild(systemOutElement);

systemOutElement.appendChild(
document.createCDATASection(out.toString())
);

Element systemErrElement = document.createElement("system-err");
testSuiteElement.appendChild(systemErrElement);

systemErrElement.appendChild(
document.createCDATASection(err.toString())
);

// write to file
FileWriter fw = new FileWriter(
reportsDir + File.separator + "TEST-" + currentTestSuiteName + ".xml"
);
StreamResult sr = new StreamResult(fw);
DOMSource source = new DOMSource(document);
trans.transform(source, sr);
fw.close();
}

public void startTestCase(Description description) throws Exception {

testCaseStartTime = System.currentTimeMillis();

testCaseElement = document.createElement("testcase");
testSuiteElement.appendChild(testCaseElement);

testCaseElement.setAttribute("classname", description.getClassName());
testCaseElement.setAttribute("name", description.getMethodName());

testCount++;
}

public void finishTestCase() throws Exception {
double time = (System.currentTimeMillis() - testCaseStartTime) / 1000.0;
testCaseElement.setAttribute("time", "" + time);
}

public void recordTestCaseSuccess() throws Exception {
successCount++;
}

public void recordTestCaseFailure(Failure failure) throws Exception {

Element failureElement = document.createElement("failure");
testCaseElement.appendChild(failureElement);

Description description = failure.getDescription();
String exceptionName = failure.getException().getClass().getName();

failureElement.setAttribute("message", failure.getMessage());
failureElement.setAttribute("type", exceptionName);

Text messageElement = document.createTextNode(
exceptionName + ": " +failure.getMessage() + "\n\tat " +
description.getClassName() + "." + description.getMethodName() + "()"
);
failureElement.appendChild(messageElement);

failureCount++;
}
}
23 changes: 23 additions & 0 deletions pki/base/common/test/com/netscape/test/TestRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.netscape.test;

import org.junit.internal.RealSystem;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;

public class TestRunner {

public Result run(String... args) throws Exception {

JUnitCore core = new JUnitCore();
core.addListener(new TestListener());

return core.runMain(new RealSystem(), args);
}

public static void main(String... args) throws Exception {

TestRunner runner = new TestRunner();
Result result = runner.run(args);
System.exit(result.wasSuccessful() ? 0 : 1);
}
}
22 changes: 17 additions & 5 deletions pki/cmake/Modules/JUnit.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,38 @@ function(add_junit_test TARGET_NAME)
set(SEPARATOR ":")
endif(WIN32 AND NOT CYGWIN)

set(REPORTS_DIR "reports")

foreach (ARG ${ARGN})
if (ARG MATCHES "CLASSPATH" OR ARG MATCHES "TESTS")
if (ARG MATCHES "(CLASSPATH|TESTS|REPORTS_DIR)")
set(TYPE ${ARG})

else (ARG MATCHES "TESTS")
else (ARG MATCHES "(CLASSPATH|TESTS|REPORTS_DIR)")

if (TYPE MATCHES "CLASSPATH")
set(CLASSPATH "${CLASSPATH}${SEPARATOR}${ARG}")

elseif (TYPE MATCHES "TESTS")
set(TESTS ${TESTS} ${ARG})

endif(TYPE MATCHES "TESTS")
elseif (TYPE MATCHES "REPORTS_DIR")
set(REPORTS_DIR ${ARG})

endif(TYPE MATCHES "CLASSPATH")

endif(ARG MATCHES "CLASSPATH" OR ARG MATCHES "TESTS")
endif(ARG MATCHES "(CLASSPATH|TESTS|REPORTS_DIR)")

endforeach(ARG)

add_custom_target(${TARGET_NAME}
COMMAND ${CMAKE_Java_RUNTIME} -classpath ${CLASSPATH} org.junit.runner.JUnitCore ${TESTS}
COMMAND
mkdir -p "${REPORTS_DIR}"
COMMAND
${CMAKE_Java_RUNTIME}
-Djunit.reports.dir=${REPORTS_DIR}
-classpath ${CLASSPATH}
com.netscape.test.TestRunner
${TESTS}
)

endfunction(add_junit_test)

0 comments on commit 343a8af

Please sign in to comment.