| opends/build-tools/src/org/opends/build/tools/CoverageDiff.java | ●●●●● patch | view | raw | blame | history | |
| opends/ext/testng/CHANGES.txt | ●●●●● patch | view | raw | blame | history | |
| opends/ext/testng/lib/testng-5.1-jdk15.jar | patch | view | raw | blame | history | |
| opends/ext/testng/lib/testng-5.4-jdk15.jar | patch | view | raw | blame | history | |
| opends/ext/testng/src.zip | patch | view | raw | blame | history | |
| opends/tests/unit-tests-testng/src/server/org/opends/server/DirectoryServerTestCase.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java | ●●●●● patch | view | raw | blame | history |
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) 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 opends/ext/testng/lib/testng-5.1-jdk15.jarBinary files differ
opends/ext/testng/lib/testng-5.4-jdk15.jarBinary files differ
opends/ext/testng/src.zipBinary files differ
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; } } opends/tests/unit-tests-testng/src/server/org/opends/server/SuiteRunner.java
New file @@ -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); } } } 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(); } } opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
New file @@ -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); } } }