From d19038d2aa112fbaa77e2ab9153a5ce4a7c2bf80 Mon Sep 17 00:00:00 2001
From: davidely <davidely@localhost>
Date: Mon, 22 Jan 2007 03:40:12 +0000
Subject: [PATCH] 1. Wrapped TestNG suite runner with our own (SuiteRunner.java). When there is an uncaught exception in the tests, this gives us the stack trace and forces the tests to exit. This should make it easier to track down OutOfMemoryErrors in the future.
---
/dev/null | 0
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java | 46 +++
opendj-sdk/opends/ext/testng/lib/testng-5.4-jdk15.jar | 0
opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java | 52 +-
opendj-sdk/opends/ext/testng/CHANGES.txt | 74 +++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java | 63 ++++
opendj-sdk/opends/ext/testng/src.zip | 0
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java | 469 +++++++++++++++++++++++++++++++++
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java | 105 -------
9 files changed, 676 insertions(+), 133 deletions(-)
diff --git a/opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java b/opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
index a86148e..3f1d287 100644
--- a/opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
+++ b/opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
@@ -77,7 +77,7 @@
private File emmaDataPath;
private File outputPath;
- private File diffPath;
+ private String diffPath;
private File svnPath;
public void setEmmaDataPath(String file)
@@ -90,9 +90,9 @@
outputPath = new File(file);
}
- public void setDiffPath(String file)
+ public void setDiffPath(String diffArgs)
{
- diffPath = new File(file);
+ diffPath = diffArgs;
}
public void setSvnPath(String file)
@@ -110,10 +110,21 @@
enabled = bol.toLowerCase().equals("true");
}
- public void execute() throws BuildException
+ public void execute() throws BuildException {
+ try {
+ innerExecute();
+ } catch (BuildException e) {
+ throw e;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void innerExecute() throws BuildException
{
long start = System.currentTimeMillis();
verboseOut("Starting to execute coveragediff.");
+ verboseOut("diffPath='" + diffPath +"'");
if(emmaDataPath == null)
{
throw new BuildException("emmaDataPath attribute is not set. It must be set to the path of the EMMA data directory");
@@ -350,7 +361,7 @@
statsTable.setClass ("it");
{
HTMLTable.IRow row = statsTable.newRow ();
- row.newCell ().setText ("base directory:", true);
+ row.newCell ().setText ("svn diff arg(s):", true);
row.newCell ().setText ("" + diffPath.toString(), true);
row = statsTable.newRow ();
@@ -461,6 +472,7 @@
modCoverage[DEL_LINES] = 0.0;
String fileHeader = diffFile.get(0);
+ verboseOut("fileHeader: " + diffFile);
//Try to get the package information if its a Java file
File srcFilePath = new File(fileHeader.substring(7));
@@ -483,8 +495,14 @@
String firstFileLine = diffFile.get(2);
String secondFileLine = diffFile.get(3);
+ verboseOut("firstFileLine=" + firstFileLine);
+ verboseOut("secondFileLine=" + secondFileLine);
String revisionStr = "unknown";
+ // Skip over binary files
+ if (firstFileLine.contains("Cannot display")) {
+ return;
+ }
HTMLTable srcTable = null;
@@ -572,7 +590,7 @@
final IElement itemname = IElement.Factory.create (Tag.SPAN);
{
- itemname.setText (toRelativePath(srcFilePath.toString()), true);
+ itemname.setText (srcFilePath.toString(), true);
itemname.setClass ("in");
}
@@ -866,7 +884,7 @@
if(nameHREF != null)
{
final String fullHREFName = anchor ? "#".concat (nameHREF) : nameHREF;
- nameCell.add(new HyperRef(fullHREFName, toRelativePath(fileName), true));
+ nameCell.add(new HyperRef(fullHREFName, fileName, true));
}
else
{
@@ -933,25 +951,7 @@
}
}
- private String createHREF(String name)
- {
- if(name == null)
- {
- return null;
- }
-
- name = name.replaceAll("[/,\\,(,),.]", "_");
-
- return name;
-
- }
-
- private String toRelativePath(String file)
- {
- return file.substring(diffPath.toString().length()+1);
- }
-
- // How does this get enabled?
+ // Enable this with -Dtest.diff.verbose=true from the commandline
private void verboseOut(Object msg)
{
if (verbose)
diff --git a/opendj-sdk/opends/ext/testng/CHANGES.txt b/opendj-sdk/opends/ext/testng/CHANGES.txt
index 1c6b0f1..8053ce5 100644
--- a/opendj-sdk/opends/ext/testng/CHANGES.txt
+++ b/opendj-sdk/opends/ext/testng/CHANGES.txt
@@ -1,7 +1,75 @@
+===========================================================================
+5.4
-TODO
- :Introduce ITestFactory, deprecate @Factory
- :Introduce Annotation Transformers
+Fixed: Ant task issue with paths containing spaces
+Added: for @BeforeGroups and @AfterGroups specifying the groups() attribute will auto-include the method
+ into those groups by default (previously you had to also provide the value() attribute).
+Added: the load @Tests (invocationCount + threadPoolSize) are triggered simultaneous
+Fixed: reports are correctly displaying the thread info
+Added: @DataProvider name defaults to method name
+Added: support for remote protocol to pass parameter information
+Fixed: TextReporter logs information about the parameters of the test methods
+Fixed: concurrency issue in JUnitXMLReporter
+Fixed: output of JUnitXMLReporter must be CDATA
+Fixed: XML unsupported annotations/parallel attribute values are reported
+
+Eclipse plug-in
+Fixed: groups with multi-attribute javadoc annotations
+Fixed: consistent behavior for dependsOnMethods
+Fixed: consistent behavior for tests with dependsOnGroups (a warning is emitted)
+Fixed: consistent merge of configuration arguments when an existing launch configuration exists
+===========================================================================
+5.3
+
+Fixed: use a single instance of bsh.Interpreter
+Added: @Before/@AfterMethod can declare a java.lang.reflect.Method parameter to be informed about the @Test method
+Fixed: super classes must not be listed in testng-failures.xml
+Fixed: parallel attribute must not appear if empty or null in testng-failures.xml
+Fixed: parsing for javadoc annotations is done on request only
+Added: improved multiple suite summary page report
+Added: -target option deprecated in favor of -annotations javadoc|jdk
+Fixed: filesets in the ant task didn't work if the paths have spaces in them
+Fixed: Before/After Suite were behaving wrong in parallel execution
+Added: A generic/extensible RemoteTestNG was added to the core
+Fixed: Before/AfterGroup-s were behaving wrong when using invocationCount, dataProvider and threadPoolSize
+Fixed: improved support for running different annotation type tests in the same suite
+Fixed: testng-failed.xml was generated even if there were no failures/skipps
+Fixed: -usedefaultlisteners was wrongly passed to JVM instead of TestNG options
+Added: Attribute dataProviderClass for @Test and @testng.test
+Fixed: Forgot to account for cases where both invocationCount and DataProviders are present
+Fixed: AfterGroups were invoked out of order with invocationCount and DataProviders
+Fixed: Reporter.getOutput() returned an empty array if a timeOut was specified
+Added: testng.xml now supports <suite-files>
+Added: ant task can receive several listeners
+Fixed: TESTNG-109 Skipped tests with expected exceptions are reported as failures
+Added: ant task can now select the parallel mode for running tests
+Fixed: ant task correctly deals with empty groups and excludedgroups parameters
+Added: ant task can override default suite and test names
+Added: comand line support for setting parallel mode, suite and test names
+
+Eclipse plug-in
+Added: Support for configuring per project usedefaultlisteners
+Added: Contextual drop-down menu on failures tab of the TestNG view to enable running/debugging method failure only
+Added: Suppport for configuring per project TestNG jar usage (project provided one or plugin provided one)
+
+===========================================================================
+5.2
+
+Added: "-usedefaultlisteners true/false" to command line and ant
+Added: EmailableReporter (from Paul Mendelson)
+Added: parallel can now be "methods" or "tests". Boolean version deprecated
+Added: TestNGAntTask now uses the @ syntax to invoke TestNG
+Added: Command line understands @ syntax
+Added: JUnitConverter uses the new syntax
+Added: -groups to JUnitConverter
+Fixed: Throw proper exception when a DataProvider declares parameters
+Added: completely revamped JUnit support (should run all kind of JUnit tests)
+Fixed: TESTNG-40 (Bug in testng-failed.xml generation)
+Fixed: TESTNG-106 (Failed "@BeforeSuite" method just skipps the last test in xml-file)
+Fixed: Success on 0 tests (http://forums.opensymphony.com/thread.jspa?threadID=41213)
+
+Eclipse plug-in
+Added: TESTNG-105 Automaticaly define TESTNG_HOME classpath variable
===========================================================================
5.1
diff --git a/opendj-sdk/opends/ext/testng/lib/testng-5.1-jdk15.jar b/opendj-sdk/opends/ext/testng/lib/testng-5.1-jdk15.jar
deleted file mode 100644
index e287861..0000000
--- a/opendj-sdk/opends/ext/testng/lib/testng-5.1-jdk15.jar
+++ /dev/null
Binary files differ
diff --git a/opendj-sdk/opends/ext/testng/lib/testng-5.4-jdk15.jar b/opendj-sdk/opends/ext/testng/lib/testng-5.4-jdk15.jar
new file mode 100644
index 0000000..1a68008
--- /dev/null
+++ b/opendj-sdk/opends/ext/testng/lib/testng-5.4-jdk15.jar
Binary files differ
diff --git a/opendj-sdk/opends/ext/testng/src.zip b/opendj-sdk/opends/ext/testng/src.zip
index 93c32ed..5b8ad56 100644
--- a/opendj-sdk/opends/ext/testng/src.zip
+++ b/opendj-sdk/opends/ext/testng/src.zip
Binary files differ
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
index a4b7ac8..171489e 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java
@@ -29,16 +29,6 @@
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
-import java.io.PrintStream;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Handler;
-import java.util.logging.Logger;
-import java.util.logging.LogManager;
-
-import org.opends.server.types.NullOutputStream;
-
/**
* This class defines a base test case that should be subclassed by all
* unit tests used by the Directory Server.
@@ -47,105 +37,14 @@
* have them include the class name.
*/
public abstract class DirectoryServerTestCase {
- // The set of loggers for which the console logger has been disabled.
- private HashMap<Logger,Handler> disabledLogHandlers;
-
- // The print stream to use for printing error messages.
- private PrintStream errorStream;
-
- // The original System.err print stream.
- private PrintStream originalSystemErr;
-
- // The original System.out print stream.
- private PrintStream originalSystemOut;
-
@BeforeSuite
public final void suppressOutput() {
- String suppressStr = System.getProperty("org.opends.test.suppressOutput");
- if ((suppressStr != null) && suppressStr.equalsIgnoreCase("true"))
- {
- System.setOut(NullOutputStream.printStream());
- System.setErr(NullOutputStream.printStream());
- errorStream = NullOutputStream.printStream();
-
- LogManager logManager = LogManager.getLogManager();
- Enumeration<String> loggerNames = logManager.getLoggerNames();
- while (loggerNames.hasMoreElements())
- {
- String loggerName = loggerNames.nextElement();
- Logger logger = logManager.getLogger(loggerName);
- for (Handler h : logger.getHandlers())
- {
- if (h instanceof ConsoleHandler)
- {
- disabledLogHandlers.put(logger, h);
- logger.removeHandler(h);
- break;
- }
- }
- }
- }
+ TestCaseUtils.suppressOutput();
}
@AfterSuite
public final void shutdownServer() {
TestCaseUtils.shutdownServer("The current test suite has finished.");
-
- System.setOut(originalSystemOut);
- System.setErr(originalSystemErr);
- errorStream = originalSystemErr;
-
- for (Logger l : disabledLogHandlers.keySet())
- {
- Handler h = disabledLogHandlers.get(l);
- l.addHandler(h);
- }
- disabledLogHandlers.clear();
+ TestCaseUtils.unsupressOutput();
}
-
- /**
- * Creates a new instance of this test case with the provided name.
- */
- protected DirectoryServerTestCase() {
- this.errorStream = System.err;
-
- disabledLogHandlers = new HashMap<Logger,Handler>();
- originalSystemOut = System.out;
- originalSystemErr = System.err;
- }
-
- /**
- * Prints the provided message to the error stream, prepending the
- * fully-qualified class name.
- *
- * @param message
- * The message to be printed to the error stream.
- */
- public final void printError(String message) {
- errorStream.print(getClass().getName());
- errorStream.print(" -- ");
- errorStream.println(message);
- }
-
- /**
- * Prints the stack trace for the provided exception to the error
- * stream.
- *
- * @param exception
- * The exception to be printed to the error stream.
- */
- public final void printException(Throwable exception) {
- exception.printStackTrace(errorStream);
- }
-
- /**
- * Specifies the error stream to which messages will be printed.
- *
- * @param errorStream
- * The error stream to which messages will be printed.
- */
- public final void setErrorStream(PrintStream errorStream) {
- this.errorStream = errorStream;
- }
-
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java
new file mode 100644
index 0000000..b3f0a70
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server;
+
+import org.testng.TestNG;
+import static org.opends.server.TestCaseUtils.originalSystemErr;
+
+/**
+ * This class wraps TestNG so that we can force the process to exit if there
+ * is an uncaught exception (e.g. OutOfMemoryError).
+ */
+public class SuiteRunner {
+ public static void main(String[] args) {
+ try {
+ TestNG.main(args);
+ } catch (Throwable e) {
+ originalSystemErr.println("TestNG.main threw an expected exception:");
+ e.printStackTrace(originalSystemErr);
+ System.exit(TestNG.HAS_FAILURE);
+ }
+ }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
index 5320654..111a25a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -33,6 +33,13 @@
import java.io.*;
import java.util.List;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.logging.Logger;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+import java.util.logging.ConsoleHandler;
import java.net.ServerSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
@@ -51,6 +58,7 @@
import org.opends.server.types.FilePermission;
import org.opends.server.types.InitializationException;
import org.opends.server.types.OperatingSystem;
+import org.opends.server.types.NullOutputStream;
import static org.testng.Assert.*;
@@ -651,7 +659,7 @@
public static String makeLdif(String... lines) {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < lines.length; i++) {
- buffer.append(lines[i]).append("\n");
+ buffer.append(lines[i]).append(EOL);
}
return buffer.toString();
}
@@ -731,4 +739,57 @@
// Ignore it.
}
}
+
+ // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
+
+ // The set of loggers for which the console logger has been disabled.
+ private final static Map<Logger, Handler> disabledLogHandlers = new HashMap<Logger,Handler>();
+
+ /** The original System.err print stream. Use this if you absolutely
+ * must write something to System.err. */
+ public final static PrintStream originalSystemErr = System.err;
+
+ /** The original System.out print stream. Use this if you absolutely
+ * must write something to System.out. */
+ public final static PrintStream originalSystemOut = System.out;
+
+ public synchronized static void suppressOutput() {
+ String suppressStr = System.getProperty("org.opends.test.suppressOutput");
+ if ((suppressStr != null) && suppressStr.equalsIgnoreCase("true"))
+ {
+ System.setOut(NullOutputStream.printStream());
+ System.setErr(NullOutputStream.printStream());
+
+ LogManager logManager = LogManager.getLogManager();
+ Enumeration<String> loggerNames = logManager.getLoggerNames();
+ while (loggerNames.hasMoreElements())
+ {
+ String loggerName = loggerNames.nextElement();
+ Logger logger = logManager.getLogger(loggerName);
+ for (Handler h : logger.getHandlers())
+ {
+ if (h instanceof ConsoleHandler)
+ {
+ disabledLogHandlers.put(logger, h);
+ logger.removeHandler(h);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public synchronized static void unsupressOutput() {
+ System.setOut(originalSystemOut);
+ System.setErr(originalSystemErr);
+
+ for (Logger l : disabledLogHandlers.keySet())
+ {
+ Handler h = disabledLogHandlers.get(l);
+ l.addHandler(h);
+ }
+ disabledLogHandlers.clear();
+ }
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
new file mode 100644
index 0000000..d472a6b
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
@@ -0,0 +1,469 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server;
+
+import org.testng.TestListenerAdapter;
+import org.testng.IReporter;
+import org.testng.ISuite;
+import org.testng.ITestResult;
+import org.testng.IClass;
+import org.testng.ITestNGMethod;
+import org.testng.ITestContext;
+import org.testng.xml.XmlSuite;
+import static org.opends.server.util.ServerConstants.EOL;
+import static org.opends.server.TestCaseUtils.originalSystemErr;
+
+import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.io.PrintStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * This class is our replacement for the test results that TestNG generates.
+ * It prints out test to the console as they happen.
+ * It
+ *
+ */
+public class TestListener extends TestListenerAdapter implements IReporter {
+ private final StringBuilder _bufferedTestFailures = new StringBuilder();
+
+ public static final String REPORT_FILE_NAME = "results.txt";
+
+ // This is used to communicate with build.xml. So that even when a test
+ // fails, we can do the coverage report before failing the build.
+ public static final String ANT_TESTS_FAILED_FILE_NAME = ".tests-failed-marker";
+
+ private static final String DIVIDER_LINE = "-------------------------------------------------------------------------------" + EOL;
+
+ public void onStart(ITestContext testContext) {
+ super.onStart(testContext);
+
+ // Delete the previous report if it's there.
+ new File(testContext.getOutputDirectory(), REPORT_FILE_NAME).delete();
+ }
+
+ public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
+ File reportFile = new File(outputDirectory, REPORT_FILE_NAME);
+
+ writeReportToFile(reportFile);
+ writeReportToScreen(reportFile);
+ writeAntTestsFailedMarker(outputDirectory);
+ }
+
+ private void writeAntTestsFailedMarker(String outputDirectory) {
+ // Signal 'ant' that all of the tests passed by removing this
+ // special file.
+ if (countTestsWithStatus(ITestResult.FAILURE) == 0) {
+ new File(outputDirectory, ANT_TESTS_FAILED_FILE_NAME).delete();
+ }
+ }
+
+ private void writeReportToFile(File reportFile) {
+ PrintStream reportStream = null;
+ try {
+ reportStream = new PrintStream(new FileOutputStream(reportFile));
+ } catch (FileNotFoundException e) {
+ originalSystemErr.println("Could not open " + reportFile + " for writing. Will write the unit test report to the console instead.");
+ e.printStackTrace(originalSystemErr);
+ reportStream = originalSystemErr;
+ }
+
+ reportStream.println(center("UNIT TEST REPORT"));
+ reportStream.println(center("----------------") + EOL);
+ reportStream.println("Finished at: " + (new Date()));
+ reportStream.println("# Test clases: " + _classResults.size());
+ reportStream.println("# Test methods: " + countTestMethods());
+ reportStream.println("# Tests passed: " + countTestsWithStatus(ITestResult.SUCCESS));
+ reportStream.println("# Tests failed: " + countTestsWithStatus(ITestResult.FAILURE));
+ reportStream.println(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL + EOL);
+ reportStream.println(center("FAILED TESTS"));
+ reportStream.println(EOL + EOL);
+ reportStream.println(_bufferedTestFailures);
+
+ reportStream.println(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL);
+
+ reportStream.println(getTimingInfo());
+
+ reportStream.close();
+ }
+
+ private String getFqMethod(ITestResult result) {
+ IClass cls = result.getTestClass();
+ ITestNGMethod method = result.getMethod();
+
+ return cls.getName() + "#" + method.getMethodName();
+ }
+
+ private void writeReportToScreen(File reportFile) {
+ List<ITestResult> failedTests = getFailedTests();
+ StringBuilder failed = new StringBuilder();
+ for (int i = 0; i < failedTests.size(); i++) {
+ ITestResult failedTest = failedTests.get(i);
+ String fqMethod = getFqMethod(failedTest);
+ int numFailures = 1;
+ // Peek ahead to see if we had multiple failures for the same method
+ // In which case, we list it once with a count of the failures.
+ while (((i + 1) < failedTests.size()) &&
+ fqMethod.equals(getFqMethod(failedTests.get(i+1)))) {
+ numFailures++;
+ i++;
+ }
+
+ failed.append(" ").append(fqMethod);
+
+ if (numFailures > 1) {
+ failed.append(" (x " + numFailures + ")");
+ }
+
+ failed.append(EOL);
+ }
+
+
+
+
+ if (failed.length() > 0) {
+ originalSystemErr.println("The following unit tests failed: ");
+ originalSystemErr.println(failed);
+ originalSystemErr.println();
+ originalSystemErr.println("Include the ant option '-Dtest.failures=true' to rerun only the failed tests.");
+ } else {
+ originalSystemErr.println("All of the tests passed.");
+ }
+
+ originalSystemErr.println();
+ originalSystemErr.println("Wrote full test report to:");
+ originalSystemErr.println(reportFile.getAbsolutePath());
+ }
+
+
+ public void onTestSuccess(ITestResult tr) {
+ super.onTestSuccess(tr);
+ addTestResult(tr);
+ }
+
+ public void onTestFailure(ITestResult tr) {
+ super.onTestFailure(tr);
+ addTestResult(tr);
+
+ IClass cls = tr.getTestClass();
+ ITestNGMethod method = tr.getMethod();
+
+ String fqMethod = cls.getName() + "#" + method.getMethodName();
+
+ StringBuilder failureInfo = new StringBuilder();
+ failureInfo.append("Failed Test: ").append(fqMethod).append(EOL);
+ Object[] parameters = tr.getParameters();
+
+
+ Throwable cause = tr.getThrowable();
+ if (cause != null) {
+ failureInfo.append("Failure Cause: ").append(getTestngLessStack(cause));
+ }
+
+ for (int i = 0; (parameters != null) && (i < parameters.length); i++) {
+ Object parameter = parameters[i];
+ failureInfo.append("parameter[" + i + "]: ").append(parameter).append(EOL);
+ }
+
+ failureInfo.append(EOL + EOL);
+ originalSystemErr.print(EOL + EOL + EOL + " T E S T F A I L U R E ! ! !" + EOL + EOL);
+ originalSystemErr.print(failureInfo);
+ originalSystemErr.print(DIVIDER_LINE + EOL + EOL);
+
+ _bufferedTestFailures.append(failureInfo);
+ }
+
+ private String getTestngLessStack(Throwable t) {
+ StackTraceElement[] elements = t.getStackTrace();
+
+ int lowestOpenDSFrame;
+ for (lowestOpenDSFrame = elements.length - 1; lowestOpenDSFrame >= 0; lowestOpenDSFrame--) {
+ StackTraceElement element = elements[lowestOpenDSFrame];
+ String clsName = element.getClassName();
+ if (clsName.startsWith("org.opends.") && !clsName.equals("org.opends.server.SuiteRunner")) {
+ break;
+ }
+ }
+
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(t).append(EOL);
+ for (int i = 0; i <= lowestOpenDSFrame; i++) {
+ buffer.append(" ").append(elements[i]).append(EOL);
+ }
+
+ return buffer.toString();
+ }
+
+
+ private final static int PAGE_WIDTH = 80;
+ private static String center(String header) {
+ StringBuilder buffer = new StringBuilder();
+ int indent = (PAGE_WIDTH - header.length()) / 2;
+ for (int i = 0; i < indent; i++) {
+ buffer.append(" ");
+ }
+ buffer.append(header);
+ return buffer.toString();
+ }
+
+
+ public void onTestSkipped(ITestResult tr) {
+ super.onTestSkipped(tr);
+ // TODO: do we need to do anything with this?
+ }
+
+ public void onTestFailedButWithinSuccessPercentage(ITestResult tr) {
+ super.onTestFailedButWithinSuccessPercentage(tr);
+ addTestResult(tr);
+ }
+
+ private void addTestResult(ITestResult result) {
+ getResultsForClass(result.getTestClass()).addTestResult(result);
+ }
+
+ private final LinkedHashMap<IClass, TestClassResults> _classResults = new LinkedHashMap<IClass, TestClassResults>();
+
+ private TestClassResults getResultsForClass(IClass cls) {
+ TestClassResults results = _classResults.get(cls);
+ if (results == null) {
+ results = new TestClassResults(cls);
+ _classResults.put(cls, results);
+ }
+ return results;
+ }
+
+ synchronized StringBuilder getTimingInfo() {
+ StringBuilder timingOutput = new StringBuilder();
+ timingOutput.append(center("TESTS RUN BY CLASS")).append(EOL);
+ timingOutput.append(center("[method-name total-time (total-invocations)]")).append(EOL + EOL);
+ for (TestClassResults results: _classResults.values()) {
+ results.getTimingInfo(timingOutput);
+ }
+
+ timingOutput.append(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL);
+
+ getSlowestTestsOutput(timingOutput);
+ return timingOutput;
+ }
+
+ private int countTestMethods() {
+ int count = 0;
+ for (TestClassResults results: _classResults.values()) {
+ count += results._methods.size();
+ }
+ return count;
+ }
+
+ private int countTestsWithStatus(int status) {
+ int count = 0;
+ for (TestClassResults results: _classResults.values()) {
+ count += results._resultCounts[status];
+ }
+ return count;
+ }
+
+ synchronized private List<TestMethodResults> getAllMethodResults() {
+ List<TestMethodResults> allResults = new ArrayList<TestMethodResults>();
+ for (TestClassResults results: _classResults.values()) {
+ allResults.addAll(results.getAllMethodResults());
+ }
+ return allResults;
+ }
+
+ private static final int NUM_SLOWEST_METHODS = 100;
+
+ private void getSlowestTestsOutput(StringBuilder timingOutput) {
+ timingOutput.append(center("CLASS SUMMARY SORTED BY DURATION")).append(EOL);
+ timingOutput.append(center("[class-name total-time (total-invocations)]")).append(EOL + EOL);
+ List<TestClassResults> sortedClasses = getClassesDescendingSortedByDuration();
+ for (int i = 0; i < sortedClasses.size(); i++) {
+ TestClassResults results = sortedClasses.get(i);
+ timingOutput.append(" ");
+ results.getSummaryTimingInfo(timingOutput);
+ timingOutput.append(EOL);
+ }
+
+ timingOutput.append(EOL + DIVIDER_LINE + EOL + EOL);
+ timingOutput.append(center("SLOWEST METHODS")).append(EOL);
+ timingOutput.append(center("[method-name total-time (total-invocations)]")).append(EOL + EOL);
+ List<TestMethodResults> sortedMethods = getMethodsDescendingSortedByDuration();
+ for (int i = 0; i < Math.min(sortedMethods.size(), NUM_SLOWEST_METHODS); i++) {
+ TestMethodResults results = sortedMethods.get(i);
+ results.getTimingInfo(timingOutput, true);
+ }
+ }
+
+
+ private List<TestMethodResults> getMethodsDescendingSortedByDuration() {
+ List<TestMethodResults> allMethods = getAllMethodResults();
+ Collections.sort(allMethods, new Comparator<TestMethodResults>() {
+ public int compare(TestMethodResults o1, TestMethodResults o2) {
+ if (o1._totalDurationMs > o2._totalDurationMs) {
+ return -1;
+ } else if (o1._totalDurationMs < o2._totalDurationMs) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ return allMethods;
+ }
+
+ private List<TestClassResults> getClassesDescendingSortedByDuration() {
+ List<TestClassResults> allClasses = new ArrayList<TestClassResults>(_classResults.values());
+ Collections.sort(allClasses, new Comparator<TestClassResults>() {
+ public int compare(TestClassResults o1, TestClassResults o2) {
+ if (o1._totalDurationMs > o2._totalDurationMs) {
+ return -1;
+ } else if (o1._totalDurationMs < o2._totalDurationMs) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ return allClasses;
+ }
+
+ private final static String[] STATUSES =
+ {"<<invalid>>", "Success", "Failure", "Skip", "Success Percentage Failure"};
+
+
+ /**
+ *
+ */
+ private static class TestClassResults {
+ private final IClass _cls;
+ private final LinkedHashMap<ITestNGMethod, TestMethodResults> _methods = new LinkedHashMap<ITestNGMethod, TestMethodResults>();
+ private int _totalInvocations = 0;
+ private long _totalDurationMs = 0;
+
+ // Indexed by SUCCESS, FAILURE, SKIP, SUCCESS_PERCENTAGE_FAILURE
+ private int[] _resultCounts = new int[STATUSES.length];
+
+ public TestClassResults(IClass cls) {
+ _cls = cls;
+ }
+
+ synchronized void addTestResult(ITestResult result) {
+ _totalInvocations++;
+ _totalDurationMs += result.getEndMillis() - result.getStartMillis();
+
+ getResultsForMethod(result.getMethod()).addTestResult(result);
+ int status = result.getStatus();
+ if (status < 0 || status >= _resultCounts.length) {
+ status = 0;
+ }
+ _resultCounts[status]++;
+ }
+
+ private TestMethodResults getResultsForMethod(ITestNGMethod method) {
+ TestMethodResults results = _methods.get(method);
+ if (results == null) {
+ results = new TestMethodResults(method);
+ _methods.put(method, results);
+ }
+ return results;
+ }
+
+ synchronized void getSummaryTimingInfo(StringBuilder timingOutput) {
+ timingOutput.append(_cls.getRealClass().getName() + " ");
+ timingOutput.append(getTotalDurationMs() + " ms" + " (" + getTotalInvocations() + ")");
+ }
+
+ synchronized Collection<TestMethodResults> getAllMethodResults() {
+ return _methods.values();
+ }
+
+ synchronized void getTimingInfo(StringBuilder timingOutput) {
+ getSummaryTimingInfo(timingOutput);
+ timingOutput.append(EOL);
+ for (TestMethodResults results: getAllMethodResults()) {
+ results.getTimingInfo(timingOutput, false);
+ }
+
+ timingOutput.append(EOL);
+ }
+
+ int getTotalInvocations() {
+ return _totalInvocations;
+ }
+
+ long getTotalDurationMs() {
+ return _totalDurationMs;
+ }
+ }
+
+
+ /**
+ *
+ */
+ private static class TestMethodResults {
+ private final ITestNGMethod _method;
+ int _totalInvocations = 0;
+ long _totalDurationMs = 0;
+
+ // Indexed by SUCCESS, FAILURE, SKIP, SUCCESS_PERCENTAGE_FAILURE
+ private int[] _resultCounts = new int[STATUSES.length];
+
+ public TestMethodResults(ITestNGMethod method) {
+ _method = method;
+ }
+
+ synchronized void addTestResult(ITestResult result) {
+ _totalInvocations++;
+ _totalDurationMs += result.getEndMillis() - result.getStartMillis();
+
+ int status = result.getStatus();
+ if (status < 0 || status >= _resultCounts.length) {
+ status = 0;
+ }
+ _resultCounts[status]++;
+ }
+
+ synchronized void getTimingInfo(StringBuilder timingOutput, boolean includeClassName) {
+ timingOutput.append(" ");
+ if (includeClassName) {
+ timingOutput.append(_method.getRealClass().getName()).append("#");
+ }
+ timingOutput.append(_method.getMethodName() + " ");
+ timingOutput.append(_totalDurationMs + " ms" + " (" + _totalInvocations + ")");
+ if (_resultCounts[ITestResult.FAILURE] > 0) {
+ timingOutput.append(" " + _resultCounts[ITestResult.FAILURE] + " failure(s)");
+ }
+ timingOutput.append(EOL);
+ }
+ }
+}
--
Gitblit v1.10.0