diff --git a/pom.xml b/pom.xml index 348ef7ec..c9b7ed8c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,234 +1,231 @@ + - 4.0.0 - - org.jenkins-ci.plugins - plugin - 4.86 - - - junit - ${changelist} - hpi - JUnit Plugin - Allows JUnit-format test results to be published. - https://github.com/jenkinsci/${project.artifactId}-plugin - - 999999-SNAPSHOT - jenkinsci/${project.artifactId}-plugin - 2.414 - ${jenkins.baseline}.3 - false - - - - MIT - https://opensource.org/licenses/MIT - - - - scm:git:https://github.com/${gitHubRepo}.git - scm:git:https://github.com/${gitHubRepo} - https://github.com/${gitHubRepo} - ${scmTag} - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - - - - repo.jenkins-ci.org - https://repo.jenkins-ci.org/public/ - - + 4.0.0 + + org.jenkins-ci.plugins + plugin + 4.86 + + + + junit + ${changelist} + hpi + JUnit Plugin + Allows JUnit-format test results to be published. + https://github.com/jenkinsci/${project.artifactId}-plugin + + + + MIT + https://opensource.org/licenses/MIT + + + + + scm:git:https://github.com/${gitHubRepo}.git + scm:git:https://github.com/${gitHubRepo} + ${scmTag} + https://github.com/${gitHubRepo} + + + + 999999-SNAPSHOT + jenkinsci/${project.artifactId}-plugin + 2.414 + ${jenkins.baseline}.3 + false + false + + + - - io.jenkins.plugins - echarts-api - - - io.jenkins.plugins - ionicons-api - - - io.jenkins.plugins - checks-api - - - io.jenkins.plugins - checks-api - test - tests - - - io.jenkins.plugins - plugin-util-api - - - org.jenkins-ci.plugins - display-url-api - - - io.jenkins.plugins - github-checks - 581.va_9669c91d6cb_ - test - - - io.jenkins.plugins - bootstrap5-api - - - org.jenkins-ci.plugins.workflow - workflow-step-api - - - org.jenkins-ci.plugins.workflow - workflow-api - - - org.jenkins-ci.plugins - script-security - - - org.mockito - mockito-core - test - - - org.jenkins-ci.plugins - matrix-project - test - - - org.jenkins-ci.plugins.workflow - workflow-cps - test - - - org.jenkins-ci.plugins.workflow - workflow-job - test - - - org.jenkins-ci.plugins.workflow - workflow-cps - tests - test - - - org.jenkins-ci.plugins.workflow - workflow-basic-steps - test - - - org.jenkins-ci.plugins.workflow - workflow-support - tests - test - - - org.jenkins-ci.plugins - pipeline-stage-step - test - - - org.jenkins-ci.plugins.workflow - workflow-durable-task-step - test - - - org.jenkinsci.plugins - pipeline-model-definition - test - - - joda-time - joda-time - - - - - org.jenkins-ci.plugins - database - test - - - org.jenkins-ci.plugins - database-h2 - test - - - io.jenkins - configuration-as-code - test - - - io.jenkins.configuration-as-code - test-harness - test - - - - commons-validator - commons-validator - - - - - org.jenkins-ci.plugins - jackson2-api - - - com.pivovarit - parallel-collectors - 2.6.1 - - - org.jenkins-ci.plugins - pipeline-utility-steps - test - - - ca.umontreal.iro.simul - ssj - 3.3.2 - - - com.google.code.gson - gson - - - - org.jfree - jcommon - - - org.jfree - jfreechart - - - + + io.jenkins.tools.bom + bom-${jenkins.baseline}.x + 2982.vdce2153031a_0 + pom + import + + + + org.jetbrains.kotlin + kotlin-bom + 2.0.10 + pom + import + - - - - io.jenkins.tools.bom - bom-${jenkins.baseline}.x - 2982.vdce2153031a_0 - import - pom - - - - org.jetbrains.kotlin - kotlin-bom - 2.0.10 - import - pom - - - + + + + + ca.umontreal.iro.simul + ssj + 3.3.2 + + + com.google.code.gson + gson + + + + org.jfree + jcommon + + + org.jfree + jfreechart + + + + + com.pivovarit + parallel-collectors + 2.6.1 + + + io.jenkins.plugins + bootstrap5-api + + + io.jenkins.plugins + checks-api + + + io.jenkins.plugins + echarts-api + + + io.jenkins.plugins + ionicons-api + + + io.jenkins.plugins + plugin-util-api + + + org.jenkins-ci.plugins + display-url-api + + + org.jenkins-ci.plugins + jackson2-api + + + org.jenkins-ci.plugins + script-security + + + org.jenkins-ci.plugins.workflow + workflow-api + + + org.jenkins-ci.plugins.workflow + workflow-step-api + + + io.jenkins + configuration-as-code + test + + + io.jenkins.configuration-as-code + test-harness + test + + + io.jenkins.plugins + checks-api + tests + test + + + io.jenkins.plugins + github-checks + 581.va_9669c91d6cb_ + test + + + org.jenkins-ci.plugins + database + test + + + org.jenkins-ci.plugins + database-h2 + test + + + org.jenkins-ci.plugins + matrix-project + test + + + org.jenkins-ci.plugins + pipeline-stage-step + test + + + org.jenkins-ci.plugins + pipeline-utility-steps + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + tests + test + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + test + + + org.jenkins-ci.plugins.workflow + workflow-job + test + + + org.jenkins-ci.plugins.workflow + workflow-support + tests + test + + + org.jenkinsci.plugins + pipeline-model-definition + test + + + org.mockito + mockito-core + test + + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + diff --git a/src/main/java/hudson/tasks/junit/CaseResult.java b/src/main/java/hudson/tasks/junit/CaseResult.java index 6439cf21..7095da0a 100644 --- a/src/main/java/hudson/tasks/junit/CaseResult.java +++ b/src/main/java/hudson/tasks/junit/CaseResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Seiji Sogabe, Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -76,6 +76,7 @@ public class CaseResult extends TestResult implements Comparable { * This field retains the method name. */ private String testName; + private transient String safeName; private boolean skipped; private boolean keepTestNames; @@ -83,10 +84,13 @@ public class CaseResult extends TestResult implements Comparable { private String errorStackTrace; private String errorDetails; private Map properties; + @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Specific method to restore it") private transient SuiteResult parent; - @SuppressFBWarnings(value = "IS2_INCONSISTENT_SYNC", justification = "Not guarded, though read in synchronized blocks") + @SuppressFBWarnings( + value = "IS2_INCONSISTENT_SYNC", + justification = "Not guarded, though read in synchronized blocks") private transient ClassResult classResult; /** @@ -96,7 +100,7 @@ public class CaseResult extends TestResult implements Comparable { * If these information are reported at the test case level, these fields are set, * otherwise null, in which case {@link SuiteResult#stdout}. */ - private String stdout,stderr; + private String stdout, stderr; /** * This test has been failing since this build number (not id.) @@ -110,7 +114,6 @@ private static float parseTime(Element testCase) { return new TimeToFloat(time).parse(); } - /** * Used to create a fake failure, when Hudson fails to load data from XML files. * Public since 1.526. @@ -141,16 +144,15 @@ public CaseResult(SuiteResult parent, String testName, String errorStackTrace, S @Restricted(Beta.class) public CaseResult( - SuiteResult parent, - String className, - String testName, - String errorDetails, - String skippedMessage, + SuiteResult parent, + String className, + String testName, + String errorDetails, + String skippedMessage, float duration, String stdout, String stderr, - String stacktrace - ) { + String stacktrace) { this.className = className; this.testName = testName; this.errorStackTrace = stacktrace; @@ -160,7 +162,7 @@ public CaseResult( this.stderr = fixNULs(stderr); this.duration = duration; this.startTime = -1; - + this.skipped = skippedMessage != null; this.skippedMessage = skippedMessage; this.properties = Collections.emptyMap(); @@ -168,31 +170,48 @@ public CaseResult( } @Deprecated - CaseResult(SuiteResult parent, Element testCase, String testClassName, boolean keepLongStdio, boolean keepProperties, boolean keepTestNames) { - this(parent, testCase, testClassName, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, keepTestNames); - } - - CaseResult(SuiteResult parent, Element testCase, String testClassName, StdioRetention stdioRetention, boolean keepProperties, boolean keepTestNames) { + CaseResult( + SuiteResult parent, + Element testCase, + String testClassName, + boolean keepLongStdio, + boolean keepProperties, + boolean keepTestNames) { + this( + parent, + testCase, + testClassName, + StdioRetention.fromKeepLongStdio(keepLongStdio), + keepProperties, + keepTestNames); + } + + CaseResult( + SuiteResult parent, + Element testCase, + String testClassName, + StdioRetention stdioRetention, + boolean keepProperties, + boolean keepTestNames) { // schema for JUnit report XML format is not available in Ant, // so I don't know for sure what means what. // reports in http://www.nabble.com/difference-in-junit-publisher-and-ant-junitreport-tf4308604.html#a12265700 // indicates that maybe I shouldn't use @classname altogether. - //String cn = testCase.attributeValue("classname"); - //if(cn==null) + // String cn = testCase.attributeValue("classname"); + // if(cn==null) // // Maven seems to skip classname, and that shows up in testSuite/@name // cn = parent.getName(); - /* - According to http://www.nabble.com/NPE-(Fatal%3A-Null)-in-recording-junit-test-results-td23562964.html - there's some odd-ball cases where testClassName is null but - @name contains fully qualified name. - */ + According to http://www.nabble.com/NPE-(Fatal%3A-Null)-in-recording-junit-test-results-td23562964.html + there's some odd-ball cases where testClassName is null but + @name contains fully qualified name. + */ String nameAttr = testCase.attributeValue("name"); - if(testClassName==null && nameAttr.contains(".")) { - testClassName = nameAttr.substring(0,nameAttr.lastIndexOf('.')); - nameAttr = nameAttr.substring(nameAttr.lastIndexOf('.')+1); + if (testClassName == null && nameAttr.contains(".")) { + testClassName = nameAttr.substring(0, nameAttr.lastIndexOf('.')); + nameAttr = nameAttr.substring(nameAttr.lastIndexOf('.') + 1); } className = testClassName; @@ -215,12 +234,13 @@ public CaseResult( Element properties_element = testCase.element("properties"); if (properties_element != null) { List property_elements = properties_element.elements("property"); - for (Element prop : property_elements){ + for (Element prop : property_elements) { if (prop.attributeValue("name") != null) { - if (prop.attributeValue("value") != null) + if (prop.attributeValue("value") != null) { properties.put(prop.attributeValue("name"), prop.attributeValue("value")); - else + } else { properties.put(prop.attributeValue("name"), prop.getText()); + } } } } @@ -249,7 +269,8 @@ public static float clampDuration(float d) { return Math.min(365.0f * 24 * 60 * 60, Math.max(0.0f, d)); } - public static CaseResult parse(SuiteResult parent, final XMLStreamReader reader, String ver) throws XMLStreamException { + public static CaseResult parse(SuiteResult parent, final XMLStreamReader reader, String ver) + throws XMLStreamException { CaseResult r = new CaseResult(parent, null, null, null); while (reader.hasNext()) { final int event = reader.next(); @@ -309,7 +330,8 @@ public static CaseResult parse(SuiteResult parent, final XMLStreamReader reader, return r; } - public static void parseProperties(Map r, final XMLStreamReader reader, String ver) throws XMLStreamException { + public static void parseProperties(Map r, final XMLStreamReader reader, String ver) + throws XMLStreamException { while (reader.hasNext()) { final int event = reader.next(); if (event == XMLStreamReader.END_ELEMENT && reader.getLocalName().equals("properties")) { @@ -330,7 +352,8 @@ public static void parseProperties(Map r, final XMLStreamReader } } - public static void parseProperty(Map r, final XMLStreamReader reader, String ver) throws XMLStreamException { + public static void parseProperty(Map r, final XMLStreamReader reader, String ver) + throws XMLStreamException { String name = null, value = null; while (reader.hasNext()) { final int event = reader.next(); @@ -357,10 +380,10 @@ public static void parseProperty(Map r, final XMLStreamReader re } } } - } - static String possiblyTrimStdio(Collection results, StdioRetention stdioRetention, String stdio) { // HUDSON-6516 + static String possiblyTrimStdio( + Collection results, StdioRetention stdioRetention, String stdio) { // HUDSON-6516 if (stdio == null) { return null; } @@ -375,7 +398,8 @@ static String possiblyTrimStdio(Collection results, StdioRetention s if (middle <= 0) { return stdio; } - return stdio.subSequence(0, halfMaxSize) + "\n...[truncated " + middle + " chars]...\n" + stdio.subSequence(len - halfMaxSize, len); + return stdio.subSequence(0, halfMaxSize) + "\n...[truncated " + middle + " chars]...\n" + + stdio.subSequence(len - halfMaxSize, len); } static String fixNULs(String stdio) { // JENKINS-71139 @@ -386,7 +410,8 @@ static String fixNULs(String stdio) { // JENKINS-71139 * Flavor of {@link #possiblyTrimStdio(Collection, StdioRetention, String)} that doesn't try to read the whole thing into memory. */ @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "Expected behavior") - static String possiblyTrimStdio(Collection results, StdioRetention stdioRetention, File stdio) throws IOException { + static String possiblyTrimStdio(Collection results, StdioRetention stdioRetention, File stdio) + throws IOException { long len = stdio.length(); boolean keepAll = stdioRetention == StdioRetention.ALL || (stdioRetention == StdioRetention.FAILED && hasFailures(results)); @@ -408,8 +433,8 @@ static String possiblyTrimStdio(Collection results, StdioRetention s int headBytes = head.getBytes().length; int tailBytes = tail.getBytes().length; - middle = len - (headBytes+tailBytes); - if (middle<=0) { + middle = len - (headBytes + tailBytes); + if (middle <= 0) { // if it turns out that we didn't have any middle section, just return the whole thing return FileUtils.readFileToString(stdio); } @@ -419,6 +444,7 @@ static String possiblyTrimStdio(Collection results, StdioRetention s private static final int HALF_MAX_SIZE = 500; private static final int HALF_MAX_FAILING_SIZE = 50000; + private static int halfMaxSize(Collection results) { return hasFailures(results) ? HALF_MAX_FAILING_SIZE : HALF_MAX_SIZE; } @@ -434,8 +460,9 @@ public ClassResult getParent() { private static String getError(Element testCase) { String msg = testCase.elementText("error"); - if(msg!=null) + if (msg != null) { return msg; + } return testCase.elementText("failure"); } @@ -466,7 +493,7 @@ private static String getSkippedMessage(Element testCase) { if (skippedElement != null) { message = skippedElement.attributeValue("message"); - if(message == null) { + if (message == null) { message = skippedElement.getText(); } } @@ -484,7 +511,8 @@ public String getDisplayName() { } private String getNameWithEnclosingBlocks(String rawName) { - // Only prepend the enclosing flow node names if there are any and the run this is in has multiple blocks directly containing + // Only prepend the enclosing flow node names if there are any and the run this is in has multiple blocks + // directly containing // test results. if (!keepTestNames && !getEnclosingFlowNodeNames().isEmpty()) { Run r = getRun(); @@ -506,7 +534,7 @@ private String getNameWithEnclosingBlocks(String rawName) { *

* Note that this may contain any URL-unfriendly character. */ - @Exported(visibility=999) + @Exported(visibility = 999) public @Override String getName() { if (testName == null || testName.isEmpty()) { return "(?)"; @@ -525,12 +553,12 @@ public String getTitle() { /** * Gets the duration of the test, in seconds */ - @Exported(visibility=9) + @Exported(visibility = 9) @Override public float getDuration() { return duration; } - + /** * Gets the start time of the test, in epoch milliseconds */ @@ -546,12 +574,13 @@ public long getStartTime() { return safeName; } StringBuilder buf = new StringBuilder(getDisplayName()); - for( int i=0; i siblings = classResult ==null ? Collections.emptyList(): classResult.getChildren(); + Collection siblings = classResult == null ? Collections.emptyList() : classResult.getChildren(); return safeName = uniquifyName(siblings, buf.toString()); } @@ -560,7 +589,7 @@ public long getStartTime() { * * @return the class name of a test class. */ - @Exported(visibility=9) + @Exported(visibility = 9) public String getClassName() { return className; } @@ -572,7 +601,7 @@ public String getClassName() { */ public String getSimpleName() { int idx = className.lastIndexOf('.'); - return className.substring(idx+1); + return className.substring(idx + 1); } /** @@ -582,13 +611,16 @@ public String getSimpleName() { */ public String getPackageName() { int idx = className.lastIndexOf('.'); - if(idx<0) return "(root)"; - else return className.substring(0,idx); + if (idx < 0) { + return "(root)"; + } else { + return className.substring(0, idx); + } } @Override public String getFullName() { - return className+'.'+getName(); + return className + '.' + getName(); } /** @@ -598,18 +630,27 @@ public String getFullName() { public String getFullDisplayName() { return getNameWithEnclosingBlocks(getTransformedFullDisplayName()); } + public String getTransformedFullDisplayName() { return TestNameTransformer.getTransformedName(getFullName()); } @Override public int getFailCount() { - if (isFailed()) return 1; else return 0; + if (isFailed()) { + return 1; + } else { + return 0; + } } @Override public int getSkipCount() { - if (isSkipped()) return 1; else return 0; + if (isSkipped()) { + return 1; + } else { + return 0; + } } @Override @@ -621,7 +662,7 @@ public int getPassCount() { * If this test failed, then return the build number * when this test started failing. */ - @Exported(visibility=9) + @Exported(visibility = 9) @Override public int getFailedSince() { // If we haven't calculated failedSince yet, and we should, @@ -631,7 +672,7 @@ public int getFailedSince() { } private void recomputeFailedSinceIfNeeded() { - if (failedSince==0 && getFailCount()==1) { + if (failedSince == 0 && getFailCount() == 1) { CaseResult prev = getPreviousResult(); if (prev != null && prev.isFailed()) { this.failedSince = prev.getFailedSince(); @@ -639,20 +680,20 @@ private void recomputeFailedSinceIfNeeded() { this.failedSince = getRun().getNumber(); } else { LOGGER.warning("trouble calculating getFailedSince. We've got prev, but no owner."); - // failedSince will be 0, which isn't correct. + // failedSince will be 0, which isn't correct. } } } @Override - public Run getFailedSinceRun() { + public Run getFailedSinceRun() { JunitTestResultStorage storage = JunitTestResultStorage.find(); if (!(storage instanceof FileJunitTestResultStorage)) { Run run = Stapler.getCurrentRequest().findAncestorObject(Run.class); TestResultImpl pluggableStorage = storage.load(run.getParent().getFullName(), run.getNumber()); return pluggableStorage.getFailedSinceRun(this); } - + return getRun().getParent().getBuildByNumber(getFailedSince()); } @@ -662,16 +703,16 @@ public Run getFailedSinceRun() { * * @return the number of consecutive failing builds. */ - @Exported(visibility=9) + @Exported(visibility = 9) public int getAge() { - if(isPassed()) + if (isPassed()) { return 0; - else if (getRun() != null) { - return getRun().getNumber()-getFailedSince()+1; + } else if (getRun() != null) { + return getRun().getNumber() - getFailedSince() + 1; } else { LOGGER.fine("Trying to get age of a CaseResult without an owner"); - return 0; - } + return 0; + } } /** @@ -690,9 +731,13 @@ else if (getRun() != null) { @Exported @Override public String getStdout() { - if(stdout!=null) return stdout; + if (stdout != null) { + return stdout; + } SuiteResult sr = getSuiteResult(); - if (sr==null) return ""; + if (sr == null) { + return ""; + } return getSuiteResult().getStdout(); } @@ -705,27 +750,34 @@ public String getStdout() { @Exported @Override public String getStderr() { - if(stderr!=null) return stderr; + if (stderr != null) { + return stderr; + } SuiteResult sr = getSuiteResult(); - if (sr==null) return ""; + if (sr == null) { + return ""; + } return getSuiteResult().getStderr(); } - static int PREVIOUS_TEST_RESULT_BACKTRACK_BUILDS_MAX = - Integer.parseInt(System.getProperty(History.HistoryTableResult.class.getName() + ".PREVIOUS_TEST_RESULT_BACKTRACK_BUILDS_MAX","25")); + static int PREVIOUS_TEST_RESULT_BACKTRACK_BUILDS_MAX = Integer.parseInt(System.getProperty( + History.HistoryTableResult.class.getName() + ".PREVIOUS_TEST_RESULT_BACKTRACK_BUILDS_MAX", "25")); @Override public CaseResult getPreviousResult() { - if (parent == null) return null; + if (parent == null) { + return null; + } TestResult previousResult = parent.getParent(); int n = 0; while (previousResult != null && n < PREVIOUS_TEST_RESULT_BACKTRACK_BUILDS_MAX) { previousResult = previousResult.getPreviousResult(); - if (previousResult == null) + if (previousResult == null) { return null; + } if (previousResult instanceof hudson.tasks.junit.TestResult) { - hudson.tasks.junit.TestResult pr = (hudson.tasks.junit.TestResult) previousResult; + hudson.tasks.junit.TestResult pr = (hudson.tasks.junit.TestResult) previousResult; CaseResult cr = pr.getCase(parent.getName(), getTransformedFullDisplayName()); if (cr != null) { return cr; @@ -744,7 +796,7 @@ public CaseResult getPreviousResult() { public TestResult findCorrespondingResult(String id) { if (id.equals(safe(getName()))) { return this; - } + } return null; } @@ -779,10 +831,11 @@ public Collection getSkippedTests() { } private Collection singletonListOfThisOrEmptyList(boolean f) { - if (f) + if (f) { return Collections.singletonList(this); - else + } else { return Collections.emptyList(); + } } /** @@ -814,7 +867,7 @@ public Map getProperties() { */ @Override public boolean isPassed() { - return !skipped && errorDetails == null && errorStackTrace==null; + return !skipped && errorDetails == null && errorStackTrace == null; } /** @@ -823,7 +876,7 @@ public boolean isPassed() { * been configured to be skipped. * @return true if the test was not executed, false otherwise. */ - @Exported(visibility=9) + @Exported(visibility = 9) public boolean isSkipped() { return skipped; } @@ -877,9 +930,9 @@ public List getEnclosingFlowNodeNames() { } @Override - public Run getRun() { + public Run getRun() { SuiteResult sr = getSuiteResult(); - if (sr==null) { + if (sr == null) { LOGGER.warning("In getOwner(), getSuiteResult is null"); return null; } @@ -896,14 +949,14 @@ public Run getRun() { public void setParentSuiteResult(SuiteResult parent) { this.parent = parent; - } + } public void freeze(SuiteResult parent) { this.parent = parent; // some old test data doesn't have failedSince value set, so for those compute them. recomputeFailedSinceIfNeeded(); } - + @Override public int compareTo(CaseResult that) { if (this == that) { @@ -931,17 +984,17 @@ public int hashCode() { return System.identityHashCode(this); } - @Exported(name="status",visibility=9) // because stapler notices suffix 's' and remove it + @Exported(name = "status", visibility = 9) // because stapler notices suffix 's' and remove it public Status getStatus() { if (skipped) { return Status.SKIPPED; } CaseResult pr = getPreviousResult(); - if(pr==null) { + if (pr == null) { return isPassed() ? Status.PASSED : Status.FAILED; } - if(pr.isPassed()) { + if (pr.isPassed()) { return isPassed() ? Status.PASSED : Status.REGRESSION; } else { return isPassed() ? Status.FIXED : Status.FAILED; @@ -951,7 +1004,7 @@ public Status getStatus() { public void setClass(ClassResult classResult) { this.classResult = classResult; } - + public void setStartTime(long start) { startTime = start; } @@ -967,34 +1020,34 @@ public enum Status { /** * This test runs OK, just like its previous run. */ - PASSED("result-passed",Messages._CaseResult_Status_Passed(),true), + PASSED("result-passed", Messages._CaseResult_Status_Passed(), true), /** * This test was skipped due to configuration or the * failure or skipping of a method that it depends on. */ - SKIPPED("result-skipped",Messages._CaseResult_Status_Skipped(),false), + SKIPPED("result-skipped", Messages._CaseResult_Status_Skipped(), false), /** * This test failed, just like its previous run. */ - FAILED("result-failed",Messages._CaseResult_Status_Failed(),false), + FAILED("result-failed", Messages._CaseResult_Status_Failed(), false), /** * This test has been failing, but now it runs OK. */ - FIXED("result-fixed",Messages._CaseResult_Status_Fixed(),true), + FIXED("result-fixed", Messages._CaseResult_Status_Fixed(), true), /** * This test has been running OK, but now it failed. */ - REGRESSION("result-regression",Messages._CaseResult_Status_Regression(),false); + REGRESSION("result-regression", Messages._CaseResult_Status_Regression(), false); private final String cssClass; private final Localizable message; public final boolean isOK; Status(String cssClass, Localizable message, boolean OK) { - this.cssClass = cssClass; - this.message = message; - isOK = OK; - } + this.cssClass = cssClass; + this.message = message; + isOK = OK; + } public String getCssClass() { return cssClass; @@ -1005,7 +1058,7 @@ public String getMessage() { } public boolean isRegression() { - return this==REGRESSION; + return this == REGRESSION; } } @@ -1015,5 +1068,4 @@ public boolean isRegression() { /*package*/ static final Comparator BY_AGE = Comparator.comparingInt(CaseResult::getAge); private static final long serialVersionUID = 1L; - } diff --git a/src/main/java/hudson/tasks/junit/ClassResult.java b/src/main/java/hudson/tasks/junit/ClassResult.java index b04df807..7ea2919a 100644 --- a/src/main/java/hudson/tasks/junit/ClassResult.java +++ b/src/main/java/hudson/tasks/junit/ClassResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, id:cactusman, Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -45,10 +45,10 @@ public final class ClassResult extends TabulatedResult implements Comparable cases = new TreeSet(); - private int passCount,failCount,skipCount; - - private float duration; - + private int passCount, failCount, skipCount; + + private float duration; + private long startTime; private final PackageResult parent; @@ -61,7 +61,7 @@ public ClassResult(PackageResult parent, String className) { @Override public Run getRun() { - return parent==null ? null: parent.getRun(); + return parent == null ? null : parent.getRun(); } @Override @@ -71,12 +71,16 @@ public PackageResult getParent() { @Override public ClassResult getPreviousResult() { - if(parent==null) return null; + if (parent == null) { + return null; + } TestResult pr = parent.getPreviousResult(); - if(pr==null) return null; - if(pr instanceof PackageResult) { - return ((PackageResult)pr).getClassResult(getName()); - } + if (pr == null) { + return null; + } + if (pr instanceof PackageResult) { + return ((PackageResult) pr).getClassResult(getName()); + } return null; } @@ -87,8 +91,8 @@ public hudson.tasks.test.TestResult findCorrespondingResult(String id) { int base = id.indexOf(myID); if (base > 0) { int caseNameStart = base + myID.length() + 1; - if (id.length() > caseNameStart) { - caseName = id.substring(caseNameStart); + if (id.length() > caseNameStart) { + caseName = id.substring(caseNameStart); } } return getCaseResult(caseName); @@ -109,12 +113,15 @@ public String getChildType() { return "case"; } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public String getName() { int idx = className.lastIndexOf('.'); - if(idx<0) return className; - else return className.substring(idx+1); + if (idx < 0) { + return className; + } else { + return className.substring(idx + 1); + } } public @Override synchronized String getSafeName() { @@ -123,11 +130,12 @@ public String getName() { } return safeName = uniquifyName(parent.getChildren(), safe(getName())); } - + public CaseResult getCaseResult(String name) { for (CaseResult c : cases) { - if(c.getSafeName().equals(name)) + if (c.getSafeName().equals(name)) { return c; + } } return null; } @@ -135,15 +143,14 @@ public CaseResult getCaseResult(String name) { @Override public Object getDynamic(String name, StaplerRequest req, StaplerResponse rsp) { CaseResult c = getCaseResult(name); - if (c != null) { + if (c != null) { return c; - } else { + } else { return super.getDynamic(name, req, rsp); - } + } } - - @Exported(name="child") + @Exported(name = "child") @Override public Collection getChildren() { return cases; @@ -157,13 +164,13 @@ public boolean hasChildren() { // TODO: wait for stapler 1.60 @Exported @Override public float getDuration() { - return duration; + return duration; } - + public long getStartTime() { return startTime; } - + @Exported @Override public int getPassCount() { @@ -196,17 +203,15 @@ public void add(CaseResult r) { */ @Override public void tally() { - passCount=failCount=skipCount=0; + passCount = failCount = skipCount = 0; duration = 0; for (CaseResult r : cases) { r.setClass(this); if (r.isSkipped()) { skipCount++; - } - else if(r.isPassed()) { + } else if (r.isPassed()) { passCount++; - } - else { + } else { failCount++; } duration += r.getDuration(); @@ -218,7 +223,7 @@ void freeze() { } public String getClassName() { - return className; + return className; } @Override @@ -252,18 +257,18 @@ public int hashCode() { public String getDisplayName() { return TestNameTransformer.getTransformedName(getName()); } - + /** * @since 1.515 */ @Override public String getFullName() { - return getParent().getName() + "." + className; + return getParent().getName() + "." + className; } - + @Override public String getFullDisplayName() { - return getParent().getDisplayName() + "." + TestNameTransformer.getTransformedName(className); + return getParent().getDisplayName() + "." + TestNameTransformer.getTransformedName(className); } /** @@ -271,14 +276,14 @@ public String getFullDisplayName() { */ @Override public String getRelativePathFrom(TestObject it) { - if(it instanceof CaseResult) { - return ".."; + if (it instanceof CaseResult) { + return ".."; } else { return super.getRelativePathFrom(it); } } - - public void setStartTime(long start) { + + public void setStartTime(long start) { this.startTime = start; } diff --git a/src/main/java/hudson/tasks/junit/History.java b/src/main/java/hudson/tasks/junit/History.java index afb161bc..21a8517b 100644 --- a/src/main/java/hudson/tasks/junit/History.java +++ b/src/main/java/hudson/tasks/junit/History.java @@ -81,7 +81,8 @@ public boolean historyAvailable() { @JavaScriptMethod @SuppressWarnings("unused") // Called by jelly view public String getTestResultTrend(int start, int end, String configuration) { - return JACKSON_FACADE.toJson(createTestResultTrend(start, end, ChartModelConfiguration.fromJson(configuration))); + return JACKSON_FACADE.toJson( + createTestResultTrend(start, end, ChartModelConfiguration.fromJson(configuration))); } private LinesChartModel createTestResultTrend(int start, int end, ChartModelConfiguration chartModelConfiguration) { @@ -89,7 +90,8 @@ private LinesChartModel createTestResultTrend(int start, int end, ChartModelConf if (pluggableStorage != null) { return new TestResultTrendChart().create(pluggableStorage.getTrendTestResultSummary()); } - return new TestResultTrendChart().createFromTestObject(createBuildHistory(testObject, start, end), chartModelConfiguration); + return new TestResultTrendChart() + .createFromTestObject(createBuildHistory(testObject, start, end), chartModelConfiguration); } private ObjectNode computeDurationTrendJson(List history) { @@ -122,7 +124,7 @@ private ObjectNode computeDurationTrendJson(List histo dashLineStyle.put("color", "rgba(128, 128, 128, 0.1)"); ArrayNode lightDashType = MAPPER.createArrayNode(); lightDashType.add(5); - lightDashType.add(10); + lightDashType.add(10); dashLineStyle.set("type", lightDashType); durationAvgMark.put("type", "average"); durationAvgMark.put("name", "Avg"); @@ -130,7 +132,7 @@ private ObjectNode computeDurationTrendJson(List histo durationAvgMark.set("lineStyle", dashLineStyle); durationMarkData.add(durationAvgMark); - float maxDuration = (float)0.0; + float maxDuration = (float) 0.0; for (HistoryTestResultSummary h : history) { if (maxDuration < h.getDuration()) { maxDuration = h.getDuration(); @@ -172,12 +174,12 @@ private ObjectNode computeDurationTrendJson(List histo double[] lrY = new double[history.size()]; for (HistoryTestResultSummary h : history) { lrX[index] = index; - Run r = h.getRun(); + Run r = h.getRun(); String fdn = r.getDisplayName(); domainAxisLabels.add(fdn); ObjectNode durationColor = MAPPER.createObjectNode(); double duration = Math.round(mul * h.getDuration() * roundMul) / roundMul; - tmpMax = Math.max((float)duration, tmpMax); + tmpMax = Math.max((float) duration, tmpMax); lrY[index] = duration; durationColor.put("value", duration); if (h.getPassCount() > 0 && h.getFailCount() == 0 && h.getSkipCount() == 0) { @@ -186,7 +188,7 @@ private ObjectNode computeDurationTrendJson(List histo if (h.getFailCount() > 0) { ObjectNode failedStyle = MAPPER.createObjectNode(); double k = Math.min(1.0, h.getFailCount() / (h.getTotalCount() * 0.02)); - failedStyle.put("color", "rgba(255, 100, 100, " + (0.5 + 0.5 * k) +")"); + failedStyle.put("color", "rgba(255, 100, 100, " + (0.5 + 0.5 * k) + ")"); durationColor.set("itemStyle", failedStyle); } else { durationColor.set("itemStyle", skippedStyle); @@ -197,24 +199,52 @@ private ObjectNode computeDurationTrendJson(List histo } if (EXTRA_GRAPH_MATH_ENABLED) { - createLinearTrend(series, history, lrX, lrY, "Trend of " + durationStr, "rgba(0, 120, 255, 0.5)", 0, 0, roundMul); // "--blue" - createSplineTrend(series, history, lrX, lrY, "Smooth of " + durationStr, "rgba(120, 50, 255, 0.5)", 0, 0, roundMul); // "--indigo" + createLinearTrend( + series, + history, + lrX, + lrY, + "Trend of " + durationStr, + "rgba(0, 120, 255, 0.5)", + 0, + 0, + roundMul); // "--blue" + createSplineTrend( + series, + history, + lrX, + lrY, + "Smooth of " + durationStr, + "rgba(120, 50, 255, 0.5)", + 0, + 0, + roundMul); // "--indigo" } root.set("series", series); root.set("domainAxisLabels", domainAxisLabels); root.put("integerRangeAxis", true); root.put("domainAxisItemName", "Build"); if (tmpMax > 50) { - root.put("rangeMax", (int)Math.ceil(tmpMax)); + root.put("rangeMax", (int) Math.ceil(tmpMax)); } else if (tmpMax > 0.0) { - root.put("rangeMax", tmpMax); - } else - root.put("rangeMin", 0); + root.put("rangeMax", tmpMax); + } else { + root.put("rangeMin", 0); + } root.set("yAxis", yAxis); return root; } - private void createLinearTrend(ArrayNode series, List history, double[] lrX, double[] lrY, String title, String color, int xAxisIndex, int yAxisIndex, double roundMul) { + private void createLinearTrend( + ArrayNode series, + List history, + double[] lrX, + double[] lrY, + String title, + String color, + int xAxisIndex, + int yAxisIndex, + double roundMul) { if (history.size() < 3) { return; } @@ -243,11 +273,20 @@ private void createLinearTrend(ArrayNode series, List } for (int index = 0; index < history.size(); ++index) { // Use float to reduce JSON size. - lrData.add((float)(Math.round((cs[0] + index * cs[1]) * roundMul) / roundMul)); + lrData.add((float) (Math.round((cs[0] + index * cs[1]) * roundMul) / roundMul)); } } - private void createSplineTrend(ArrayNode series, List history, double[] lrX, double[] lrY, String title, String color, int xAxisIndex, int yAxisIndex, double roundMul) { + private void createSplineTrend( + ArrayNode series, + List history, + double[] lrX, + double[] lrY, + String title, + String color, + int xAxisIndex, + int yAxisIndex, + double roundMul) { if (history.size() < 200) { return; } @@ -279,12 +318,12 @@ private void createSplineTrend(ArrayNode series, List } for (int index = 0; index < history.size(); ++index) { // Use float to reduce JSON size. - lrData.add((float)(Math.round(scs.evaluate(index) * roundMul) / roundMul)); + lrData.add((float) (Math.round(scs.evaluate(index) * roundMul) / roundMul)); } } static boolean EXTRA_GRAPH_MATH_ENABLED = - Boolean.parseBoolean(System.getProperty(History.class.getName() + ".EXTRA_GRAPH_MATH_ENABLED","true")); + Boolean.parseBoolean(System.getProperty(History.class.getName() + ".EXTRA_GRAPH_MATH_ENABLED", "true")); private ObjectNode computeResultTrendJson(List history) { ObjectNode root = MAPPER.createObjectNode(); @@ -308,7 +347,7 @@ private ObjectNode computeResultTrendJson(List history ObjectNode okAreaStyle = MAPPER.createObjectNode(); okSeries.set("areaStyle", okAreaStyle); okAreaStyle.put("normal", true); - + ObjectNode okMarkLine = MAPPER.createObjectNode(); okSeries.set("markLine", okMarkLine); ArrayNode okMarkData = MAPPER.createArrayNode(); @@ -321,7 +360,7 @@ private ObjectNode computeResultTrendJson(List history dashLineStyle.put("color", "rgba(128, 128, 128, 0.1)"); ArrayNode lightDashType = MAPPER.createArrayNode(); lightDashType.add(5); - lightDashType.add(10); + lightDashType.add(10); dashLineStyle.set("type", lightDashType); avgMark.put("type", "average"); avgMark.put("name", "Avg"); @@ -341,7 +380,7 @@ private ObjectNode computeResultTrendJson(List history failSeries.set("data", failData); ObjectNode failStyle = MAPPER.createObjectNode(); failSeries.set("itemStyle", failStyle); - failStyle.put("color", "--light-red"); //"rgba(200, 50, 50, 0.8)"); + failStyle.put("color", "--light-red"); // "rgba(200, 50, 50, 0.8)"); failSeries.put("stack", "stacked"); ObjectNode failAreaStyle = MAPPER.createObjectNode(); failSeries.set("areaStyle", failAreaStyle); @@ -381,7 +420,7 @@ private ObjectNode computeResultTrendJson(List history lineStyle.put("type", "dashed"); ObjectNode totalStyle = MAPPER.createObjectNode(); totalSeries.set("itemStyle", totalStyle); - totalStyle.put("color", "--light-blue"); //"rgba(0, 255, 255, 0.6)"); + totalStyle.put("color", "--light-blue"); // "rgba(0, 255, 255, 0.6)"); ObjectNode totalAreaStyle = MAPPER.createObjectNode(); totalSeries.set("areaStyle", totalAreaStyle); @@ -391,14 +430,14 @@ private ObjectNode computeResultTrendJson(List history series.add(failSeries); series.add(okSeries); series.add(totalSeries); - + int maxTotalCount = 0; int index = 0; double[] lrX = new double[history.size()]; double[] lrY = new double[history.size()]; for (HistoryTestResultSummary h : history) { lrX[index] = index; - Run r = h.getRun(); + Run r = h.getRun(); String fdn = r.getDisplayName(); domainAxisLabels.add(fdn); lrY[index] = h.getPassCount(); @@ -413,8 +452,18 @@ private ObjectNode computeResultTrendJson(List history } if (EXTRA_GRAPH_MATH_ENABLED) { - createLinearTrend(series, history, lrX, lrY, "Trend of Passed", "rgba(50, 50, 255, 0.5)" , 1, 1, 10.0); // "--dark-blue" - createSplineTrend(series, history, lrX, lrY, "Smooth of Passed", "rgba(255, 50, 255, 0.5)", 1, 1, 10.0); // "--purple" + createLinearTrend( + series, + history, + lrX, + lrY, + "Trend of Passed", + "rgba(50, 50, 255, 0.5)", + 1, + 1, + 10.0); // "--dark-blue" + createSplineTrend( + series, history, lrX, lrY, "Smooth of Passed", "rgba(255, 50, 255, 0.5)", 1, 1, 10.0); // "--purple" } root.set("series", series); @@ -440,14 +489,14 @@ private ObjectNode computeDistributionJson(List histor durationSeries.set("data", durationData); ObjectNode durationStyle = MAPPER.createObjectNode(); durationSeries.set("itemStyle", durationStyle); - durationStyle.put("color", "--success-color");//"rgba(50, 200, 50, 0.8)"); + durationStyle.put("color", "--success-color"); // "rgba(50, 200, 50, 0.8)"); durationSeries.put("stack", "stacked"); ObjectNode durAreaStyle = MAPPER.createObjectNode(); durationSeries.set("areaStyle", durAreaStyle); durAreaStyle.put("color", "rgba(0,0,0,0)"); durationSeries.put("smooth", true); series.add(durationSeries); - + double maxDuration = 0, minDuration = Double.MAX_VALUE; for (HistoryTestResultSummary h : history) { if (maxDuration < h.getDuration()) { @@ -467,7 +516,7 @@ private ObjectNode computeDistributionJson(List histor double scale = maxDuration - minDuration; double step = scale / counts.length; for (HistoryTestResultSummary h : history) { - int idx = smoothBuffer + (int)Math.round((h.getDuration() - minDuration) / step); + int idx = smoothBuffer + (int) Math.round((h.getDuration() - minDuration) / step); int idx2 = Math.max(0, Math.min(idx, lrY.length - 1)); lrY[idx2]++; } @@ -484,7 +533,7 @@ private ObjectNode computeDistributionJson(List histor } else if (maxDuration < 1) { xAxis.put("name", "Duration (milliseconds)"); mul = 1e3; - } else if (maxDuration < 90) { + } else if (maxDuration < 90) { xAxis.put("name", "Duration (seconds)"); mul = 1.0; } else if (maxDuration < 90 * 60) { @@ -500,14 +549,14 @@ private ObjectNode computeDistributionJson(List histor int maxBuilds = 0; SmoothingCubicSpline scs = new SmoothingCubicSpline(lrX, lrY, 0.1); int smoothPts = counts.length * 4; - double k = (double)counts.length / smoothPts; + double k = (double) counts.length / smoothPts; final double splineRoundMul = 1000.0; for (double z = minDuration; z < maxDuration; z += step * k) { double v = Math.round(splineRoundMul * Math.max(0.0, scs.evaluate(z / scale * 100.0))) / splineRoundMul; - durationData.add((float)v); - maxBuilds = Math.max(maxBuilds, (int)Math.ceil(v)); + durationData.add((float) v); + maxBuilds = Math.max(maxBuilds, (int) Math.ceil(v)); // Use float for smaller JSONs. - domainAxisLabels.add((float)(Math.round(mul * z * roundMul) / roundMul)); + domainAxisLabels.add((float) (Math.round(mul * z * roundMul) / roundMul)); } root.set("series", series); @@ -524,7 +573,7 @@ private ObjectNode computeDistributionJson(List histor private ObjectNode computeBuildMapJson(List history) { ObjectNode buildMap = MAPPER.createObjectNode(); for (HistoryTestResultSummary h : history) { - Run r = h.getRun(); + Run r = h.getRun(); String fdn = r.getDisplayName(); ObjectNode buildObj = MAPPER.createObjectNode(); buildObj.put("url", h.getUrl()); @@ -543,7 +592,11 @@ private ObjectNode computeTrendJsons(HistoryParseResult parseResult) { root.set("buildMap", computeBuildMapJson(history)); ObjectNode saveAsImage = MAPPER.createObjectNode(); if (!history.isEmpty()) { - saveAsImage.put("name", "test-history-" + history.get(0).getRun().getParent().getFullName() + "-" + history.get(0).getRun().getNumber() + "-" + history.get(history.size() - 1).getRun().getNumber()); + saveAsImage.put( + "name", + "test-history-" + history.get(0).getRun().getParent().getFullName() + "-" + + history.get(0).getRun().getNumber() + "-" + + history.get(history.size() - 1).getRun().getNumber()); } else { saveAsImage.put("name", "test-history"); } @@ -572,9 +625,14 @@ private TestResultImpl getPluggableStorage() { } else if (testObject instanceof PackageResult) { pluggableStorage = ((PackageResult) testObject).getParent().getPluggableStorage(); } else if (testObject instanceof ClassResult) { - pluggableStorage = ((ClassResult) testObject).getParent().getParent().getPluggableStorage(); + pluggableStorage = + ((ClassResult) testObject).getParent().getParent().getPluggableStorage(); } else if (testObject instanceof CaseResult) { - pluggableStorage = ((CaseResult) testObject).getParent().getParent().getParent().getPluggableStorage(); + pluggableStorage = ((CaseResult) testObject) + .getParent() + .getParent() + .getParent() + .getPluggableStorage(); } return pluggableStorage; } @@ -587,7 +645,8 @@ public static class HistoryTableResult { public HistoryTableResult(HistoryParseResult parseResult, ObjectNode json) { this.historySummaries = parseResult.historySummaries; - this.descriptionAvailable = this.historySummaries.stream().anyMatch(summary -> summary.getDescription() != null); + this.descriptionAvailable = + this.historySummaries.stream().anyMatch(summary -> summary.getDescription() != null); this.trendChartJson = json.toString(); this.parseResult = parseResult; } @@ -614,7 +673,16 @@ public static class HistoryParseResult { int end; int interval; boolean hasTimedOut; - public HistoryParseResult(List historySummaries, int buildsRequested, int buildsParsed, int buildsWithTestResult, boolean hasTimedOut, int start, int end, int interval) { + + public HistoryParseResult( + List historySummaries, + int buildsRequested, + int buildsParsed, + int buildsWithTestResult, + boolean hasTimedOut, + int start, + int end, + int interval) { this.buildsRequested = buildsRequested; this.historySummaries = historySummaries; this.buildsParsed = buildsParsed; @@ -624,7 +692,9 @@ public HistoryParseResult(List historySummaries, int b this.end = end; this.interval = interval; } - public HistoryParseResult(List historySummaries, int buildsRequested, int start, int end) { + + public HistoryParseResult( + List historySummaries, int buildsRequested, int start, int end) { this(historySummaries, buildsRequested, -1, -1, false, start, end, 1); } } @@ -640,7 +710,10 @@ public HistoryTableResult retrieveHistorySummary(int start, int end) { public HistoryTableResult retrieveHistorySummary(int start, int end, int interval) { synchronized (cachedResultLock) { HistoryTableResult result = cachedResult.get(); - if (result != null && result.parseResult.start == start && result.parseResult.end == end && result.parseResult.interval == interval) { + if (result != null + && result.parseResult.start == start + && result.parseResult.end == end + && result.parseResult.interval == interval) { return result; } TestResultImpl pluggableStorage = getPluggableStorage(); @@ -662,12 +735,15 @@ public HistoryTableResult retrieveHistorySummary(int start, int end, int interva } } - static int parallelism = Math.min(Runtime.getRuntime().availableProcessors(), Math.max(4, (int)(Runtime.getRuntime().availableProcessors() * 0.75 * 0.75))); - static ExecutorService executor = Executors.newFixedThreadPool(Math.max(4, (int)(Runtime.getRuntime().availableProcessors() * 0.75 * 0.75))); + static int parallelism = Math.min(Runtime.getRuntime().availableProcessors(), Math.max(4, (int) + (Runtime.getRuntime().availableProcessors() * 0.75 * 0.75))); + static ExecutorService executor = + Executors.newFixedThreadPool(Math.max(4, (int) (Runtime.getRuntime().availableProcessors() * 0.75 * 0.75))); static long MAX_TIME_ELAPSED_RETRIEVING_HISTORY_NS = - SystemProperties.getLong(History.class.getName() + ".MAX_TIME_ELAPSED_RETRIEVING_HISTORY_MS", 15000L) * 1000000L; + SystemProperties.getLong(History.class.getName() + ".MAX_TIME_ELAPSED_RETRIEVING_HISTORY_MS", 15000L) + * 1000000L; static int MAX_THREADS_RETRIEVING_HISTORY = - SystemProperties.getInteger(History.class.getName() + ".MAX_THREADS_RETRIEVING_HISTORY",-1); + SystemProperties.getInteger(History.class.getName() + ".MAX_THREADS_RETRIEVING_HISTORY", -1); private HistoryParseResult getHistoryFromFileStorage(int start, int end, int interval) { TestObject testObject = getTestObject(); @@ -678,43 +754,53 @@ private HistoryParseResult getHistoryFromFileStorage(int start, int end, int int final long startedNs = java.lang.System.nanoTime(); final AtomicInteger orderedCount = new AtomicInteger(0); List history = builds.stream() - .skip(start) - .limit(requestedCount) - .filter(build -> { - if (interval == 1) { - return true; - } - int n = orderedCount.getAndIncrement(); - return (n % interval) == 0; - }) - .collect(ParallelCollectors.parallel(build -> { - // Do not navigate too far or for too long, we need to finish the request this year and have to think about RAM - if ((java.lang.System.nanoTime() - startedNs) > MAX_TIME_ELAPSED_RETRIEVING_HISTORY_NS) { - hasTimedOut.set(true); - return null; - } - parsedCount.incrementAndGet(); - hudson.tasks.test.TestResult resultInRun = testObject.getResultInRun(build); - if (resultInRun == null) { - return null; - } - - return new HistoryTestResultSummary(build, resultInRun.getDuration(), - resultInRun.getFailCount(), - resultInRun.getSkipCount(), - resultInRun.getPassCount(), - resultInRun.getDescription() - ); - }, executor, MAX_THREADS_RETRIEVING_HISTORY < 1 ? parallelism : Math.min(parallelism, MAX_THREADS_RETRIEVING_HISTORY))) - .join() - .filter(Objects::nonNull) - .collect(Collectors.toList()); - return new HistoryParseResult(history, requestedCount, parsedCount.get(), history.size(), hasTimedOut.get(), start, end, interval); + .skip(start) + .limit(requestedCount) + .filter(build -> { + if (interval == 1) { + return true; + } + int n = orderedCount.getAndIncrement(); + return (n % interval) == 0; + }) + .collect(ParallelCollectors.parallel( + build -> { + // Do not navigate too far or for too long, we need to finish the request this year and have + // to think about RAM + if ((java.lang.System.nanoTime() - startedNs) > MAX_TIME_ELAPSED_RETRIEVING_HISTORY_NS) { + hasTimedOut.set(true); + return null; + } + parsedCount.incrementAndGet(); + hudson.tasks.test.TestResult resultInRun = testObject.getResultInRun(build); + if (resultInRun == null) { + return null; + } + + return new HistoryTestResultSummary( + build, + resultInRun.getDuration(), + resultInRun.getFailCount(), + resultInRun.getSkipCount(), + resultInRun.getPassCount(), + resultInRun.getDescription()); + }, + executor, + MAX_THREADS_RETRIEVING_HISTORY < 1 + ? parallelism + : Math.min(parallelism, MAX_THREADS_RETRIEVING_HISTORY))) + .join() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + return new HistoryParseResult( + history, requestedCount, parsedCount.get(), history.size(), hasTimedOut.get(), start, end, interval); } @SuppressWarnings("unused") // Called by jelly view public static int asInt(String s, int defaultValue) { - if (s == null) return defaultValue; + if (s == null) { + return defaultValue; + } try { return Integer.parseInt(s); } catch (NumberFormatException e) { diff --git a/src/main/java/hudson/tasks/junit/HistoryTestResultSummary.java b/src/main/java/hudson/tasks/junit/HistoryTestResultSummary.java index c51d579d..693ace6f 100644 --- a/src/main/java/hudson/tasks/junit/HistoryTestResultSummary.java +++ b/src/main/java/hudson/tasks/junit/HistoryTestResultSummary.java @@ -13,12 +13,12 @@ public class HistoryTestResultSummary { private final int passCount; private final String description; - public HistoryTestResultSummary(Run run, - float duration, int failCount, int skipCount, int passCount) { + public HistoryTestResultSummary(Run run, float duration, int failCount, int skipCount, int passCount) { this(run, duration, failCount, skipCount, passCount, null); } - public HistoryTestResultSummary(Run run, float duration, int failCount, int skipCount, int passCount, String description) { + public HistoryTestResultSummary( + Run run, float duration, int failCount, int skipCount, int passCount, String description) { this.run = run; this.duration = duration; this.failCount = failCount; @@ -60,7 +60,7 @@ public int getTotalCount() { } public float getBadness() { - return (float)Math.min(1.0, failCount / (getTotalCount() * 0.02)); + return (float) Math.min(1.0, failCount / (getTotalCount() * 0.02)); } public String getFullDisplayName() { diff --git a/src/main/java/hudson/tasks/junit/JUnitParser.java b/src/main/java/hudson/tasks/junit/JUnitParser.java index 2729e4de..a604a0a7 100644 --- a/src/main/java/hudson/tasks/junit/JUnitParser.java +++ b/src/main/java/hudson/tasks/junit/JUnitParser.java @@ -71,7 +71,7 @@ public JUnitParser() { */ @Deprecated public JUnitParser(boolean keepLongStdio) { - this(keepLongStdio , false, false, false); + this(keepLongStdio, false, false, false); } /** @@ -85,16 +85,23 @@ public JUnitParser(boolean keepLongStdio, boolean allowEmptyResults) { } @Deprecated - public JUnitParser(boolean keepLongStdio, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { + public JUnitParser( + boolean keepLongStdio, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { this(StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, allowEmptyResults, skipOldReports, false); } @Deprecated - public JUnitParser(StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { + public JUnitParser( + StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports) { this(stdioRetention, keepProperties, allowEmptyResults, skipOldReports, false); } - public JUnitParser(StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean skipOldReports, boolean keepTestNames) { + public JUnitParser( + StdioRetention stdioRetention, + boolean keepProperties, + boolean allowEmptyResults, + boolean skipOldReports, + boolean keepTestNames) { this.stdioRetention = stdioRetention; this.keepProperties = keepProperties; this.allowEmptyResults = allowEmptyResults; @@ -113,34 +120,64 @@ public String getTestResultLocationMessage() { } @Deprecated - @Override public TestResult parse(String testResultLocations, AbstractBuild build, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { + @Override + public TestResult parse(String testResultLocations, AbstractBuild build, Launcher launcher, TaskListener listener) + throws InterruptedException, IOException { return (TestResult) super.parse(testResultLocations, build, launcher, listener); } @Deprecated @Override - public TestResult parseResult(String testResultLocations, Run build, FilePath workspace, - Launcher launcher, TaskListener listener) + public TestResult parseResult( + String testResultLocations, Run build, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { return parseResult(testResultLocations, build, null, workspace, launcher, listener); } @Override - public TestResult parseResult(String testResultLocations, Run build, PipelineTestDetails pipelineTestDetails, - FilePath workspace, Launcher launcher, TaskListener listener) + public TestResult parseResult( + String testResultLocations, + Run build, + PipelineTestDetails pipelineTestDetails, + FilePath workspace, + Launcher launcher, + TaskListener listener) throws InterruptedException, IOException { - return workspace.act(new DirectParseResultCallable(testResultLocations, build, stdioRetention, keepProperties, allowEmptyResults, keepTestNames, - pipelineTestDetails, listener, skipOldReports)); + return workspace.act(new DirectParseResultCallable( + testResultLocations, + build, + stdioRetention, + keepProperties, + allowEmptyResults, + keepTestNames, + pipelineTestDetails, + listener, + skipOldReports)); } - public TestResultSummary summarizeResult(String testResultLocations, Run build, PipelineTestDetails pipelineTestDetails, - FilePath workspace, Launcher launcher, TaskListener listener, JunitTestResultStorage storage) + public TestResultSummary summarizeResult( + String testResultLocations, + Run build, + PipelineTestDetails pipelineTestDetails, + FilePath workspace, + Launcher launcher, + TaskListener listener, + JunitTestResultStorage storage) throws InterruptedException, IOException { - return workspace.act(new StorageParseResultCallable(testResultLocations, build, stdioRetention, keepProperties, allowEmptyResults, keepTestNames, - pipelineTestDetails, listener, storage.createRemotePublisher(build), skipOldReports)); + return workspace.act(new StorageParseResultCallable( + testResultLocations, + build, + stdioRetention, + keepProperties, + allowEmptyResults, + keepTestNames, + pipelineTestDetails, + listener, + storage.createRemotePublisher(build), + skipOldReports)); } - private static abstract class ParseResultCallable extends MasterToSlaveFileCallable { + private abstract static class ParseResultCallable extends MasterToSlaveFileCallable { private static final Logger LOGGER = Logger.getLogger(ParseResultCallable.class.getName()); @@ -158,10 +195,16 @@ private static abstract class ParseResultCallable extends MasterToSlaveFileCa private boolean skipOldReports; - private ParseResultCallable(String testResults, Run build, - StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean keepTestNames, - PipelineTestDetails pipelineTestDetails, TaskListener listener, - boolean skipOldReports) { + private ParseResultCallable( + String testResults, + Run build, + StdioRetention stdioRetention, + boolean keepProperties, + boolean allowEmptyResults, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails, + TaskListener listener, + boolean skipOldReports) { this.buildStartTimeInMillis = build.getStartTimeInMillis(); this.buildTimeInMillis = build.getTimeInMillis(); this.testResults = testResults; @@ -184,14 +227,22 @@ public T invoke(File ws, VirtualChannel channel) throws IOException { String[] files = ds.getIncludedFiles(); if (files.length > 0) { // not sure we can rely seriously on those timestamp so let's take the smaller one... - long filesTimestamp = Math.min(buildStartTimeInMillis,buildTimeInMillis); + long filesTimestamp = Math.min(buildStartTimeInMillis, buildTimeInMillis); // previous mode buildStartTimeInMillis + (nowSlave - nowMaster); - if(LOGGER.isLoggable(Level.FINE)) { + if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("buildStartTimeInMillis:" + buildStartTimeInMillis - + ",buildTimeInMillis:" + buildTimeInMillis + ",filesTimestamp:" + filesTimestamp + ",nowSlave:" + + ",buildTimeInMillis:" + buildTimeInMillis + ",filesTimestamp:" + filesTimestamp + + ",nowSlave:" + nowSlave + ",nowMaster:" + nowMaster); } - result = new TestResult(filesTimestamp, ds, stdioRetention, keepProperties, keepTestNames, pipelineTestDetails, skipOldReports); + result = new TestResult( + filesTimestamp, + ds, + stdioRetention, + keepProperties, + keepTestNames, + pipelineTestDetails, + skipOldReports); result.tally(); } else { if (this.allowEmptyResults) { @@ -206,30 +257,63 @@ public T invoke(File ws, VirtualChannel channel) throws IOException { } protected abstract T handle(TestResult result) throws IOException; - } private static final class DirectParseResultCallable extends ParseResultCallable { - DirectParseResultCallable(String testResults, Run build, StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean keepTestNames, - PipelineTestDetails pipelineTestDetails, TaskListener listener, boolean skipOldReports) { - super(testResults, build, stdioRetention, keepProperties, allowEmptyResults, keepTestNames, pipelineTestDetails, listener, skipOldReports); + DirectParseResultCallable( + String testResults, + Run build, + StdioRetention stdioRetention, + boolean keepProperties, + boolean allowEmptyResults, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails, + TaskListener listener, + boolean skipOldReports) { + super( + testResults, + build, + stdioRetention, + keepProperties, + allowEmptyResults, + keepTestNames, + pipelineTestDetails, + listener, + skipOldReports); } @Override protected TestResult handle(TestResult result) throws IOException { return result; } - } private static final class StorageParseResultCallable extends ParseResultCallable { private final JunitTestResultStorage.RemotePublisher publisher; - StorageParseResultCallable(String testResults, Run build, StdioRetention stdioRetention, boolean keepProperties, boolean allowEmptyResults, boolean keepTestNames, - PipelineTestDetails pipelineTestDetails, TaskListener listener, JunitTestResultStorage.RemotePublisher publisher, boolean skipOldReports) { - super(testResults, build, stdioRetention, keepProperties, allowEmptyResults, keepTestNames, pipelineTestDetails, listener, skipOldReports); + StorageParseResultCallable( + String testResults, + Run build, + StdioRetention stdioRetention, + boolean keepProperties, + boolean allowEmptyResults, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails, + TaskListener listener, + JunitTestResultStorage.RemotePublisher publisher, + boolean skipOldReports) { + super( + testResults, + build, + stdioRetention, + keepProperties, + allowEmptyResults, + keepTestNames, + pipelineTestDetails, + listener, + skipOldReports); this.publisher = publisher; } @@ -238,7 +322,5 @@ protected TestResultSummary handle(TestResult result) throws IOException { publisher.publish(result, super.listener); return new TestResultSummary(result); } - } - } diff --git a/src/main/java/hudson/tasks/junit/JUnitResultArchiver.java b/src/main/java/hudson/tasks/junit/JUnitResultArchiver.java index 73763394..2051c9e9 100644 --- a/src/main/java/hudson/tasks/junit/JUnitResultArchiver.java +++ b/src/main/java/hudson/tasks/junit/JUnitResultArchiver.java @@ -102,6 +102,7 @@ public class JUnitResultArchiver extends Recorder implements SimpleBuildStep, JU * If true, don't throw exception on missing test results or no files found. */ private boolean allowEmptyResults; + private boolean skipPublishingChecks; private String checksName; /** @@ -119,8 +120,8 @@ public JUnitResultArchiver(String testResults) { } @Deprecated - public JUnitResultArchiver(String testResults, - DescribableList> testDataPublishers) { + public JUnitResultArchiver( + String testResults, DescribableList> testDataPublishers) { this(testResults, false, testDataPublishers); } @@ -148,25 +149,38 @@ public JUnitResultArchiver( } @Deprecated - private TestResult parse(String expandedTestResults, Run run, @NonNull FilePath workspace, Launcher launcher, TaskListener listener) - throws IOException, InterruptedException - { + private TestResult parse( + String expandedTestResults, + Run run, + @NonNull FilePath workspace, + Launcher launcher, + TaskListener listener) + throws IOException, InterruptedException { return parse(this, null, expandedTestResults, run, workspace, launcher, listener); - } - private static TestResult parse(@NonNull JUnitTask task, PipelineTestDetails pipelineTestDetails, - String expandedTestResults, Run run, @NonNull FilePath workspace, - Launcher launcher, TaskListener listener) + private static TestResult parse( + @NonNull JUnitTask task, + PipelineTestDetails pipelineTestDetails, + String expandedTestResults, + Run run, + @NonNull FilePath workspace, + Launcher launcher, + TaskListener listener) throws IOException, InterruptedException { - return new JUnitParser(task.getParsedStdioRetention(), task.isKeepProperties(), task.isAllowEmptyResults(), task.isSkipOldReports(), task.isKeepTestNames()) + return new JUnitParser( + task.getParsedStdioRetention(), + task.isKeepProperties(), + task.isAllowEmptyResults(), + task.isSkipOldReports(), + task.isKeepTestNames()) .parseResult(expandedTestResults, run, pipelineTestDetails, workspace, launcher, listener); } @Deprecated - protected TestResult parse(String expandedTestResults, AbstractBuild build, Launcher launcher, BuildListener listener) - throws IOException, InterruptedException - { + protected TestResult parse( + String expandedTestResults, AbstractBuild build, Launcher launcher, BuildListener listener) + throws IOException, InterruptedException { final FilePath workspace = build.getWorkspace(); if (workspace == null) { throw new IllegalArgumentException("The provided build has no workspace"); @@ -175,17 +189,23 @@ protected TestResult parse(String expandedTestResults, AbstractBuild build, Laun } @Override - public void perform(Run build, FilePath workspace, Launcher launcher, - TaskListener listener) throws InterruptedException, IOException { - if (parseAndSummarize(this, null, build, workspace, launcher, listener).getFailCount() > 0 && !skipMarkingBuildUnstable) { + public void perform(Run build, FilePath workspace, Launcher launcher, TaskListener listener) + throws InterruptedException, IOException { + if (parseAndSummarize(this, null, build, workspace, launcher, listener).getFailCount() > 0 + && !skipMarkingBuildUnstable) { build.setResult(Result.UNSTABLE); } } /** @deprecated use {@link #parseAndSummarize} instead */ @Deprecated - public static TestResultAction parseAndAttach(@NonNull JUnitTask task, PipelineTestDetails pipelineTestDetails, - Run build, FilePath workspace, Launcher launcher, TaskListener listener) + public static TestResultAction parseAndAttach( + @NonNull JUnitTask task, + PipelineTestDetails pipelineTestDetails, + Run build, + FilePath workspace, + Launcher launcher, + TaskListener listener) throws InterruptedException, IOException { listener.getLogger().println(Messages.JUnitResultArchiver_Recording()); @@ -241,8 +261,13 @@ public static TestResultAction parseAndAttach(@NonNull JUnitTask task, PipelineT } } - public static TestResultSummary parseAndSummarize(@NonNull JUnitTask task, PipelineTestDetails pipelineTestDetails, - Run build, FilePath workspace, Launcher launcher, TaskListener listener) + public static TestResultSummary parseAndSummarize( + @NonNull JUnitTask task, + PipelineTestDetails pipelineTestDetails, + Run build, + FilePath workspace, + Launcher launcher, + TaskListener listener) throws InterruptedException, IOException { JunitTestResultStorage storage = JunitTestResultStorage.find(); if (storage instanceof FileJunitTestResultStorage) { @@ -258,7 +283,12 @@ public static TestResultSummary parseAndSummarize(@NonNull JUnitTask task, Pipel summary = null; // see below } else { result = new TestResult(storage.load(build.getParent().getFullName(), build.getNumber())); // irrelevant - summary = new JUnitParser(task.getParsedStdioRetention(), task.isKeepProperties(), task.isAllowEmptyResults(), task.isSkipOldReports(), task.isKeepTestNames()) + summary = new JUnitParser( + task.getParsedStdioRetention(), + task.isKeepProperties(), + task.isAllowEmptyResults(), + task.isSkipOldReports(), + task.isKeepTestNames()) .summarizeResult(testResults, build, pipelineTestDetails, workspace, launcher, listener, storage); } @@ -306,7 +336,8 @@ public static TestResultSummary parseAndSummarize(@NonNull JUnitTask task, Pipel } if (!task.isSkipPublishingChecks()) { - // If we haven't been provided with a checks name, and we have pipeline test details, set the checks name + // If we haven't been provided with a checks name, and we have pipeline test details, set the checks + // name // to be a ' / '-joined string of the enclosing blocks names, plus 'Tests' at the start. If there are no // enclosing blocks, you'll end up with just 'Tests'. String checksName = task.getChecksName(); @@ -339,8 +370,8 @@ public static TestResultSummary parseAndSummarize(@NonNull JUnitTask task, Pipel * @throws IOException if an error occurs. * @deprecated since 2009-08-10. */ - protected TestResult parseResult(DirectoryScanner ds, long buildTime) - throws IOException { + @Deprecated + protected TestResult parseResult(DirectoryScanner ds, long buildTime) throws IOException { return new TestResult(buildTime, ds); } @@ -364,7 +395,8 @@ public double getHealthScaleFactor() { * * @since 1.2-beta-1 */ - @DataBoundSetter public final void setHealthScaleFactor(double healthScaleFactor) { + @DataBoundSetter + public final void setHealthScaleFactor(double healthScaleFactor) { this.healthScaleFactor = Math.max(0.0, healthScaleFactor); } @@ -379,7 +411,8 @@ public List getTestDataPublishers() { * * @since 1.2 */ - @DataBoundSetter public final void setTestDataPublishers(@NonNull List testDataPublishers) { + @DataBoundSetter + public final void setTestDataPublishers(@NonNull List testDataPublishers) { this.testDataPublishers = new DescribableList<>(Saveable.NOOP); this.testDataPublishers.addAll(testDataPublishers); } @@ -390,10 +423,12 @@ public List getTestDataPublishers() { * @since 1.2-beta-1 */ @Deprecated - @DataBoundSetter public final void setKeepLongStdio(boolean keepLongStdio) { + @DataBoundSetter + public final void setKeepLongStdio(boolean keepLongStdio) { this.stdioRetention = StdioRetention.fromKeepLongStdio(keepLongStdio).name(); } + @Override @Deprecated public boolean isKeepLongStdio() { return StdioRetention.ALL == getParsedStdioRetention(); @@ -410,7 +445,8 @@ public String getStdioRetention() { /** * @param stdioRetention How to keep long stdio. */ - @DataBoundSetter public final void setStdioRetention(String stdioRetention) { + @DataBoundSetter + public final void setStdioRetention(String stdioRetention) { this.stdioRetention = stdioRetention; } @@ -422,13 +458,15 @@ public boolean isKeepProperties() { return keepProperties; } - @DataBoundSetter public final void setKeepProperties(boolean keepProperties) { + @DataBoundSetter + public final void setKeepProperties(boolean keepProperties) { this.keepProperties = keepProperties; } /** * @return the keepTestNames */ + @Override public boolean isKeepTestNames() { return keepTestNames; } @@ -436,7 +474,8 @@ public boolean isKeepTestNames() { /** * @param keepTestNames Whether to avoid prepending the parallel stage name to test name. */ - @DataBoundSetter public final void setKeepTestNames(boolean keepTestNames) { + @DataBoundSetter + public final void setKeepTestNames(boolean keepTestNames) { this.keepTestNames = keepTestNames; } @@ -474,7 +513,8 @@ public void setChecksName(String checksName) { this.checksName = checksName; } - @DataBoundSetter public final void setAllowEmptyResults(boolean allowEmptyResults) { + @DataBoundSetter + public final void setAllowEmptyResults(boolean allowEmptyResults) { this.allowEmptyResults = allowEmptyResults; } @@ -514,9 +554,8 @@ public String getDisplayName() { * @return the validation result. * @throws IOException if an error occurs. */ - public FormValidation doCheckTestResults( - @AncestorInPath AbstractProject project, - @QueryParameter String value) throws IOException { + public FormValidation doCheckTestResults(@AncestorInPath AbstractProject project, @QueryParameter String value) + throws IOException { if (project == null || !project.hasPermission(Item.WORKSPACE)) { return FormValidation.ok(); } @@ -529,13 +568,12 @@ public boolean isApplicable(Class jobType) { } public FormValidation doCheckHealthScaleFactor(@QueryParameter double value) { - if (value < 1e-7) return FormValidation.warning("Test health reporting disabled"); + if (value < 1e-7) { + return FormValidation.warning("Test health reporting disabled"); + } return FormValidation.ok(Messages.JUnitResultArchiver_HealthScaleFactorAnalysis( - 1, - (int) (100.0 - Math.max(0.0, Math.min(100.0, 1 * value))), - 5, - (int) (100.0 - Math.max(0.0, Math.min(100.0, 5 * value))) - )); + 1, (int) (100.0 - Math.max(0.0, Math.min(100.0, 1 * value))), 5, (int) + (100.0 - Math.max(0.0, Math.min(100.0, 5 * value))))); } public ListBoxModel doFillStdioRetentionItems(@QueryParameter("stdioRetention") String value) { @@ -545,15 +583,11 @@ public ListBoxModel doFillStdioRetentionItems(@QueryParameter("stdioRetention") try { selectedOption = StdioRetention.parse(value); } catch (IllegalArgumentException e) { - selectedOption = StdioRetention.DEFAULT; + selectedOption = StdioRetention.DEFAULT; } for (StdioRetention option : StdioRetention.values()) { - result.add(new ListBoxModel.Option( - option.getDisplayName(), - option.name(), - option == selectedOption - )); + result.add(new ListBoxModel.Option(option.getDisplayName(), option.name(), option == selectedOption)); } return result; diff --git a/src/main/java/hudson/tasks/junit/JUnitTask.java b/src/main/java/hudson/tasks/junit/JUnitTask.java index 4161d175..209db156 100644 --- a/src/main/java/hudson/tasks/junit/JUnitTask.java +++ b/src/main/java/hudson/tasks/junit/JUnitTask.java @@ -23,11 +23,10 @@ default StdioRetention getParsedStdioRetention() { boolean isKeepTestNames(); boolean isAllowEmptyResults(); - + boolean isSkipPublishingChecks(); String getChecksName(); boolean isSkipOldReports(); - } diff --git a/src/main/java/hudson/tasks/junit/PackageResult.java b/src/main/java/hudson/tasks/junit/PackageResult.java index ab3d70c6..6403a449 100644 --- a/src/main/java/hudson/tasks/junit/PackageResult.java +++ b/src/main/java/hudson/tasks/junit/PackageResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, id:cactusman, Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -49,29 +49,30 @@ public final class PackageResult extends MetaTabulatedResult implements Comparab /** * All {@link ClassResult}s keyed by their short name. */ - private final Map classes = new TreeMap<>(); - private int passCount,failCount,skipCount; + private final Map classes = new TreeMap<>(); + + private int passCount, failCount, skipCount; private final hudson.tasks.junit.TestResult parent; - private float duration; - private long startTime; + private float duration; + private long startTime; public PackageResult(hudson.tasks.junit.TestResult parent, String packageName) { this.packageName = packageName; this.parent = parent; this.startTime = -1; } - + @Override - public Run getRun() { + public Run getRun() { return parent == null ? null : parent.getRun(); } @Override public hudson.tasks.junit.TestResult getParent() { - return parent; + return parent; } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public String getName() { return packageName; @@ -83,9 +84,7 @@ public synchronized String getSafeName() { return safeName; } Collection siblings = parent == null ? Collections.emptyList() : parent.getChildren(); - return safeName = uniquifyName( - siblings, - safe(getName())); + return safeName = uniquifyName(siblings, safe(getName())); } @Override @@ -96,8 +95,9 @@ public TestResult findCorrespondingResult(String id) { String className = id; // fall back value if (base > 0) { int classNameStart = base + myID.length() + 1; - if (classNameStart getChildren() { return classes.values(); @@ -197,17 +198,17 @@ public boolean hasChildren() { public List getFailedTests() { TestResultImpl pluggableStorage = parent.getPluggableStorage(); if (pluggableStorage != null) { - return pluggableStorage.getFailedTestsByPackage(packageName); - } - + return pluggableStorage.getFailedTestsByPackage(packageName); + } + List r = new ArrayList<>(); for (ClassResult clr : classes.values()) { for (CaseResult cr : clr.getChildren()) { if (cr.isFailed()) { r.add(cr); + } } } - } return r; } @@ -256,8 +257,8 @@ public List getSkippedTests() { TestResultImpl pluggableStorage = parent.getPluggableStorage(); if (pluggableStorage != null) { return pluggableStorage.getSkippedTestsByPackage(packageName); - } - + } + List r = new ArrayList<>(); for (ClassResult clr : classes.values()) { for (CaseResult cr : clr.getChildren()) { @@ -270,22 +271,22 @@ public List getSkippedTests() { return r; } -// /** -// * If this test failed, then return the build number -// * when this test started failing. -// */ -// @Override -// TODO: implement! public int getFailedSince() { -// return 0; // (FIXME: generated) -// } -// /** -// * If this test failed, then return the run -// * when this test started failing. -// */ -// TODO: implement! @Override -// public Run getFailedSinceRun() { -// return null; // (FIXME: generated) -// } + // /** + // * If this test failed, then return the build number + // * when this test started failing. + // */ + // @Override + // TODO: implement! public int getFailedSince() { + // return 0; // (FIXME: generated) + // } + // /** + // * If this test failed, then return the run + // * when this test started failing. + // */ + // TODO: implement! @Override + // public Run getFailedSinceRun() { + // return null; // (FIXME: generated) + // } /** * @return true if every test was not skipped and every test did not fail, false otherwise. */ @@ -298,10 +299,10 @@ public void add(CaseResult r) { String n = r.getSimpleName(), sn = safe(n); ClassResult c = getClassResult(sn); if (c == null) { - classes.put(sn,c=new ClassResult(this,n)); + classes.put(sn, c = new ClassResult(this, n)); } c.add(r); - duration += r.getDuration(); + duration += r.getDuration(); } /** @@ -364,7 +365,7 @@ public int hashCode() { public String getDisplayName() { return TestNameTransformer.getTransformedName(packageName); } - + public void setStartTime(long time) { startTime = time; } diff --git a/src/main/java/hudson/tasks/junit/StdioRetention.java b/src/main/java/hudson/tasks/junit/StdioRetention.java index dedfe0e3..a828bd47 100644 --- a/src/main/java/hudson/tasks/junit/StdioRetention.java +++ b/src/main/java/hudson/tasks/junit/StdioRetention.java @@ -5,7 +5,6 @@ import java.util.stream.Stream; public enum StdioRetention { - ALL(Messages.StdioRetention_All_DisplayName()), FAILED(Messages.StdioRetention_Failed_DisplayName()), NONE(Messages.StdioRetention_None_DisplayName()); @@ -35,10 +34,8 @@ public static StdioRetention parse(String value) { } catch (IllegalArgumentException e) { throw new IllegalArgumentException( "Unrecognized value '" + value + "'; must be one of the following: " - + Stream.of(values()).map(Enum::name).collect(Collectors.joining(", ")), - e - ); + + Stream.of(values()).map(Enum::name).collect(Collectors.joining(", ")), + e); } } - } diff --git a/src/main/java/hudson/tasks/junit/SuiteResult.java b/src/main/java/hudson/tasks/junit/SuiteResult.java index ee726a1e..746da3ee 100644 --- a/src/main/java/hudson/tasks/junit/SuiteResult.java +++ b/src/main/java/hudson/tasks/junit/SuiteResult.java @@ -107,6 +107,7 @@ public final class SuiteResult implements Serializable { * All test cases. */ private List cases = new ArrayList<>(); + private transient Map casesByName; private transient hudson.tasks.junit.TestResult parent; @@ -118,7 +119,8 @@ public final class SuiteResult implements Serializable { /** * @since 1.22 */ - public SuiteResult(String name, String stdout, String stderr, @CheckForNull PipelineTestDetails pipelineTestDetails) { + public SuiteResult( + String name, String stdout, String stderr, @CheckForNull PipelineTestDetails pipelineTestDetails) { this.name = name; this.stderr = CaseResult.fixNULs(stderr); this.stdout = CaseResult.fixNULs(stdout); @@ -181,7 +183,8 @@ public static SuiteResult parse(final XMLStreamReader reader, String ver) throws r.id = reader.getElementText(); break; case "duration": - r.duration = Math.max(0.0f, Math.min(365 * 24 * 60 * 60, new TimeToFloat(reader.getElementText()).parse())); + r.duration = Math.max( + 0.0f, Math.min(365 * 24 * 60 * 60, new TimeToFloat(reader.getElementText()).parse())); break; case "startTime": r.startTime = Long.parseLong(reader.getElementText()); @@ -221,7 +224,8 @@ public static SuiteResult parse(final XMLStreamReader reader, String ver) throws return r; } - public static void parseEnclosingBlocks(SuiteResult r, final XMLStreamReader reader, String ver) throws XMLStreamException { + public static void parseEnclosingBlocks(SuiteResult r, final XMLStreamReader reader, String ver) + throws XMLStreamException { while (reader.hasNext()) { final int event = reader.next(); if (event == XMLStreamReader.END_ELEMENT && reader.getLocalName().equals("enclosingBlocks")) { @@ -235,14 +239,16 @@ public static void parseEnclosingBlocks(SuiteResult r, final XMLStreamReader rea break; default: if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.finest("SuiteResult.parseEnclosingBlocks encountered an unknown field: " + elementName); + LOGGER.finest( + "SuiteResult.parseEnclosingBlocks encountered an unknown field: " + elementName); } } } } } - public static void parseEnclosingBlockNames(SuiteResult r, final XMLStreamReader reader, String ver) throws XMLStreamException { + public static void parseEnclosingBlockNames(SuiteResult r, final XMLStreamReader reader, String ver) + throws XMLStreamException { while (reader.hasNext()) { final int event = reader.next(); if (event == XMLStreamReader.END_ELEMENT && reader.getLocalName().equals("enclosingBlockNames")) { @@ -256,13 +262,14 @@ public static void parseEnclosingBlockNames(SuiteResult r, final XMLStreamReader break; default: if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.finest("SuiteResult.parseEnclosingBlockNames encountered an unknown field: " + elementName); + LOGGER.finest("SuiteResult.parseEnclosingBlockNames encountered an unknown field: " + + elementName); } } } } } - + public static void parseCases(SuiteResult r, final XMLStreamReader reader, String ver) throws XMLStreamException { while (reader.hasNext()) { final int event = reader.next(); @@ -282,7 +289,6 @@ public static void parseCases(SuiteResult r, final XMLStreamReader reader, Strin } } } - } private synchronized Map casesByName() { @@ -317,15 +323,27 @@ static List parse(File xmlReport, boolean keepLongStdio, PipelineTe } @Deprecated - static List parse(File xmlReport, boolean keepLongStdio, boolean keepProperties, PipelineTestDetails pipelineTestDetails) + static List parse( + File xmlReport, boolean keepLongStdio, boolean keepProperties, PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException, InterruptedException { - return parse(xmlReport, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, false, pipelineTestDetails); + return parse( + xmlReport, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, false, pipelineTestDetails); } @Deprecated - static List parse(File xmlReport, boolean keepLongStdio, boolean keepProperties, boolean keepTestNames, PipelineTestDetails pipelineTestDetails) + static List parse( + File xmlReport, + boolean keepLongStdio, + boolean keepProperties, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException, InterruptedException { - return parse(xmlReport, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, keepTestNames, pipelineTestDetails); + return parse( + xmlReport, + StdioRetention.fromKeepLongStdio(keepLongStdio), + keepProperties, + keepTestNames, + pipelineTestDetails); } /** @@ -333,14 +351,19 @@ static List parse(File xmlReport, boolean keepLongStdio, boolean ke * This method returns a collection, as a single XML may have multiple <testsuite> * elements wrapped into the top-level <testsuites>. */ - static List parse(File xmlReport, StdioRetention stdioRetention, boolean keepProperties, boolean keepTestNames, PipelineTestDetails pipelineTestDetails) + static List parse( + File xmlReport, + StdioRetention stdioRetention, + boolean keepProperties, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException, InterruptedException { List r = new ArrayList<>(); // parse into DOM SAXReader saxReader = new SAXReader(); - //source: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet => SAXReader + // source: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet => SAXReader // setFeatureQuietly(saxReader, "http://apache.org/xml/features/disallow-doctype-decl", true); // setFeatureQuietly(saxReader, "http://xml.org/sax/features/external-parameter-entities", false); @@ -362,44 +385,64 @@ static List parse(File xmlReport, StdioRetention stdioRetention, bo private static void setFeatureQuietly(SAXReader reader, String feature, boolean value) { try { reader.setFeature(feature, value); - } - catch (SAXException ignored) { + } catch (SAXException ignored) { // ignore and continue in case the feature cannot be changed } } - private static void parseSuite(File xmlReport, StdioRetention stdioRetention, boolean keepProperties, boolean keepTestNames, List r, Element root, - PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException { + private static void parseSuite( + File xmlReport, + StdioRetention stdioRetention, + boolean keepProperties, + boolean keepTestNames, + List r, + Element root, + PipelineTestDetails pipelineTestDetails) + throws DocumentException, IOException { // nested test suites List testSuites = root.elements("testsuite"); - for (Element suite : testSuites) + for (Element suite : testSuites) { parseSuite(xmlReport, stdioRetention, keepProperties, keepTestNames, r, suite, pipelineTestDetails); + } // child test cases // FIXME: do this also if no testcases! - if (root.element("testcase") != null || root.element("error") != null) + if (root.element("testcase") != null || root.element("error") != null) { r.add(new SuiteResult(xmlReport, root, stdioRetention, keepProperties, keepTestNames, pipelineTestDetails)); + } } - private SuiteResult(File xmlReport, Element suite, StdioRetention stdioRetention, @CheckForNull PipelineTestDetails pipelineTestDetails) + private SuiteResult( + File xmlReport, + Element suite, + StdioRetention stdioRetention, + @CheckForNull PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException { - this(xmlReport, suite, stdioRetention, false, false, pipelineTestDetails); + this(xmlReport, suite, stdioRetention, false, false, pipelineTestDetails); } /** * @param xmlReport A JUnit XML report file whose top level element is 'testsuite'. * @param suite The parsed result of {@code xmlReport} */ - private SuiteResult(File xmlReport, Element suite, StdioRetention stdioRetention, boolean keepProperties, boolean keepTestNames, @CheckForNull PipelineTestDetails pipelineTestDetails) + private SuiteResult( + File xmlReport, + Element suite, + StdioRetention stdioRetention, + boolean keepProperties, + boolean keepTestNames, + @CheckForNull PipelineTestDetails pipelineTestDetails) throws DocumentException, IOException { this.file = xmlReport.getAbsolutePath(); String name = suite.attributeValue("name"); - if (name == null) + if (name == null) { // some user reported that name is null in their environment. // see http://www.nabble.com/Unexpected-Null-Pointer-Exception-in-Hudson-1.131-tf4314802.html name = '(' + xmlReport.getName() + ')'; - else { + } else { String pkg = suite.attributeValue("package"); - if (pkg != null && pkg.length() > 0) name = pkg + '.' + name; + if (pkg != null && pkg.length() > 0) { + name = pkg + '.' + name; + } } this.name = TestObject.safe(name); this.timestamp = suite.attributeValue("timestamp"); @@ -409,12 +452,11 @@ private SuiteResult(File xmlReport, Element suite, StdioRetention stdioRetention this.enclosingBlocks.addAll(pipelineTestDetails.getEnclosingBlocks()); this.enclosingBlockNames.addAll(pipelineTestDetails.getEnclosingBlockNames()); } - + // check for timestamp attribute and set start time if present if (timestamp != null && !timestamp.equals("")) { this.startTime = parseTime(timestamp); - } - else { + } else { this.startTime = -1; } @@ -451,7 +493,7 @@ private SuiteResult(File xmlReport, Element suite, StdioRetention stdioRetention // are at odds with each other --- when both are present, // one wants to use @name from , // the other wants to use @classname from . - + CaseResult caze = new CaseResult(this, e, classname, stdioRetention, keepProperties, keepTestNames); // If timestamp is present for set startTime of new CaseResult. @@ -462,7 +504,7 @@ private SuiteResult(File xmlReport, Element suite, StdioRetention stdioRetention // Else estimate start time using sum of previous case durations in suite else if (startTime != -1) { caze.setStartTime(startTime + caseStartOffset); - caseStartOffset += (long)(caze.getDuration() * 1000); + caseStartOffset += (long) (caze.getDuration() * 1000); } addCase(caze); } @@ -470,7 +512,8 @@ else if (startTime != -1) { String stdout = CaseResult.possiblyTrimStdio(cases, stdioRetention, suite.elementText("system-out")); String stderr = CaseResult.possiblyTrimStdio(cases, stdioRetention, suite.elementText("system-err")); if (stdout == null && stderr == null) { - // Surefire never puts stdout/stderr in the XML. Instead, it goes to a separate file (when ${maven.test.redirectTestOutputToFile}). + // Surefire never puts stdout/stderr in the XML. Instead, it goes to a separate file (when + // ${maven.test.redirectTestOutputToFile}). Matcher m = SUREFIRE_FILENAME.matcher(xmlReport.getName()); if (m.matches()) { // look for ***-output.txt from TEST-***.xml @@ -494,12 +537,13 @@ else if (startTime != -1) { Element properties_element = suite.element("properties"); if (properties_element != null) { List property_elements = properties_element.elements("property"); - for (Element prop : property_elements){ + for (Element prop : property_elements) { if (prop.attributeValue("name") != null) { - if (prop.attributeValue("value") != null) + if (prop.attributeValue("value") != null) { properties.put(prop.attributeValue("name"), prop.attributeValue("value")); - else + } else { properties.put(prop.attributeValue("name"), prop.getText()); + } } } } @@ -511,8 +555,8 @@ public void addCase(CaseResult cr) { cases.add(cr); casesByName().put(cr.getTransformedFullDisplayName(), cr); - //if suite time was not specified use sum of the cases' times - if( !hasTimeAttr() ){ + // if suite time was not specified use sum of the cases' times + if (!hasTimeAttr()) { duration += cr.getDuration(); } } @@ -524,12 +568,12 @@ private boolean hasTimeAttr() { return time != null; } - @Exported(visibility=9) + @Exported(visibility = 9) public String getName() { return name; } - @Exported(visibility=9) + @Exported(visibility = 9) public float getDuration() { return duration; } @@ -539,7 +583,7 @@ public float getDuration() { * * @since 1.22 */ - @Exported(visibility=9) + @Exported(visibility = 9) @CheckForNull public String getNodeId() { return nodeId; @@ -550,7 +594,7 @@ public String getNodeId() { * * @since 1.22 */ - @Exported(visibility=9) + @Exported(visibility = 9) @NonNull public List getEnclosingBlocks() { if (enclosingBlocks != null) { @@ -565,7 +609,7 @@ public List getEnclosingBlocks() { * * @since 1.22 */ - @Exported(visibility=9) + @Exported(visibility = 9) @NonNull public List getEnclosingBlockNames() { if (enclosingBlockNames != null) { @@ -622,34 +666,37 @@ public hudson.tasks.junit.TestResult getParent() { return parent; } - @Exported(visibility=9) + @Exported(visibility = 9) public String getTimestamp() { return timestamp; } - + public long getStartTime() { - return startTime; + return startTime; } - + public void setStartTime(long start) { - this.startTime = start; + this.startTime = start; } - @Exported(visibility=9) + @Exported(visibility = 9) public String getId() { return id; } - @Exported(inline=true,visibility=9) + @Exported(inline = true, visibility = 9) public List getCases() { return cases; } public SuiteResult getPreviousResult() { hudson.tasks.test.TestResult pr = parent.getPreviousResult(); - if(pr==null) return null; - if(pr instanceof hudson.tasks.junit.TestResult) - return ((hudson.tasks.junit.TestResult)pr).getSuite(name); + if (pr == null) { + return null; + } + if (pr instanceof hudson.tasks.junit.TestResult) { + return ((hudson.tasks.junit.TestResult) pr).getSuite(name); + } return null; } @@ -684,15 +731,17 @@ public void setParent(hudson.tasks.junit.TestResult parent) { } /*package*/ boolean freeze(hudson.tasks.junit.TestResult owner) { - if(this.parent!=null) - return false; // already frozen + if (this.parent != null) { + return false; // already frozen + } this.parent = owner; - for (CaseResult c : cases) + for (CaseResult c : cases) { c.freeze(this); + } return true; } - + /** * Parses time as epoch milli from time string * @param time @@ -701,9 +750,10 @@ public void setParent(hudson.tasks.junit.TestResult parent) { public long parseTime(String time) { try { // if time is not in supported format due to missing zulu and offset - if (time.charAt(time.length() - 1) != 'Z' && !time.contains("+") && time.lastIndexOf("-") <= 7) + if (time.charAt(time.length() - 1) != 'Z' && !time.contains("+") && time.lastIndexOf("-") <= 7) { time += 'Z'; - OffsetDateTime odt = OffsetDateTime.parse(time.replace(" ", "")); + } + OffsetDateTime odt = OffsetDateTime.parse(time.replace(" ", "")); return odt.toInstant().toEpochMilli(); } catch (Exception e) { // If time format causes error in parsing print message and return -1 @@ -718,12 +768,14 @@ public long parseTime(String time) { /** * Merges another SuiteResult into this one. - * + * * @param sr the SuiteResult to merge into this one */ public void merge(SuiteResult sr) { - if (sr.hasTimeAttr() ^ hasTimeAttr()){ - LOGGER.warning("Merging of suiteresults with incompatible time attribute may lead to incorrect durations in reports.( "+getFile()+", "+sr.getFile()+")"); + if (sr.hasTimeAttr() ^ hasTimeAttr()) { + LOGGER.warning( + "Merging of suiteresults with incompatible time attribute may lead to incorrect durations in reports.( " + + getFile() + ", " + sr.getFile() + ")"); } if (hasTimeAttr()) { duration += sr.getDuration(); diff --git a/src/main/java/hudson/tasks/junit/TestAction.java b/src/main/java/hudson/tasks/junit/TestAction.java index f4db1b6a..890c6e19 100644 --- a/src/main/java/hudson/tasks/junit/TestAction.java +++ b/src/main/java/hudson/tasks/junit/TestAction.java @@ -27,7 +27,7 @@ import org.kohsuke.stapler.export.ExportedBean; /** - * + * * Jelly (all optional): *

    *
  • index.jelly: included at the top of the test page
  • @@ -38,7 +38,7 @@ *
  • packagetableheader.jelly: allows additional table headers to be shown in tables that list test packages
  • *
  • tablerow.jelly: allows additional table cells to be shown in tables that list test methods, classes and packages
  • *
- * + * * @author tom * @since 1.320 * @see TestDataPublisher @@ -46,14 +46,13 @@ @ExportedBean public abstract class TestAction implements Action { - /** - * Returns text with annotations. - * @param text Text to annotate. - * - * @return the text with the annotations. - */ - public String annotate(String text) { - return text; - } - + /** + * Returns text with annotations. + * @param text Text to annotate. + * + * @return the text with the annotations. + */ + public String annotate(String text) { + return text; + } } diff --git a/src/main/java/hudson/tasks/junit/TestDataPublisher.java b/src/main/java/hudson/tasks/junit/TestDataPublisher.java index b6d2ca50..f9c9ab4d 100644 --- a/src/main/java/hudson/tasks/junit/TestDataPublisher.java +++ b/src/main/java/hudson/tasks/junit/TestDataPublisher.java @@ -46,7 +46,7 @@ * claim test failures, allowing people to file bugs, or more generally, additional actions, views, etc. * *

- * To register your implementation, put {@link Extension} on your descriptor implementation. + * To register your implementation, put {@link Extension} on your descriptor implementation. * * @since 1.320 */ @@ -72,9 +72,9 @@ public abstract class TestDataPublisher extends AbstractDescribableImpl run, @NonNull FilePath workspace, Launcher launcher, - TaskListener listener, TestResult testResult) throws IOException, InterruptedException { + public TestResultAction.Data contributeTestData( + Run run, @NonNull FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) + throws IOException, InterruptedException { if (run instanceof AbstractBuild && listener instanceof BuildListener) { return getTestData((AbstractBuild) run, launcher, (BuildListener) listener, testResult); } else { @@ -83,10 +83,18 @@ public TestResultAction.Data contributeTestData( } @Deprecated - public TestResultAction.Data getTestData( - AbstractBuild build, Launcher launcher, - BuildListener listener, TestResult testResult) throws IOException, InterruptedException { - if (Util.isOverridden(TestDataPublisher.class, getClass(), "contributeTestData", Run.class, FilePath.class, Launcher.class, TaskListener.class, TestResult.class)) { + public TestResultAction.Data getTestData( + AbstractBuild build, Launcher launcher, BuildListener listener, TestResult testResult) + throws IOException, InterruptedException { + if (Util.isOverridden( + TestDataPublisher.class, + getClass(), + "contributeTestData", + Run.class, + FilePath.class, + Launcher.class, + TaskListener.class, + TestResult.class)) { FilePath workspace = build.getWorkspace(); if (workspace == null) { throw new IOException("no workspace in " + build); @@ -97,8 +105,7 @@ public TestResultAction.Data getTestData( } } - public static DescriptorExtensionList> all() { - return Jenkins.get().getDescriptorList(TestDataPublisher.class); - } - + public static DescriptorExtensionList> all() { + return Jenkins.get().getDescriptorList(TestDataPublisher.class); + } } diff --git a/src/main/java/hudson/tasks/junit/TestDurationResultSummary.java b/src/main/java/hudson/tasks/junit/TestDurationResultSummary.java index b16fa8a9..44b189f9 100644 --- a/src/main/java/hudson/tasks/junit/TestDurationResultSummary.java +++ b/src/main/java/hudson/tasks/junit/TestDurationResultSummary.java @@ -6,7 +6,7 @@ import java.util.Map; public class TestDurationResultSummary implements Serializable { - + private final int buildNumber; private final int duration; @@ -24,7 +24,7 @@ public Map toMap() { public int getBuildNumber() { return buildNumber; } - + public String getDisplayName() { return "#" + buildNumber; } diff --git a/src/main/java/hudson/tasks/junit/TestNameTransformer.java b/src/main/java/hudson/tasks/junit/TestNameTransformer.java index e73c1210..66bb3fcc 100644 --- a/src/main/java/hudson/tasks/junit/TestNameTransformer.java +++ b/src/main/java/hudson/tasks/junit/TestNameTransformer.java @@ -14,7 +14,6 @@ * * @since 1.515 */ - public abstract class TestNameTransformer implements ExtensionPoint { /** * Transform the class/package/method name. @@ -27,7 +26,7 @@ public abstract class TestNameTransformer implements ExtensionPoint { * need to be changed. */ public abstract String transformName(String name); - + public static String getTransformedName(String name) { if (!JenkinsJVM.isJenkinsJVM()) { // TODO JENKINS-61787 should this be serialized and passed along in the callable? diff --git a/src/main/java/hudson/tasks/junit/TestObject.java b/src/main/java/hudson/tasks/junit/TestObject.java index 17b68754..fde050f3 100644 --- a/src/main/java/hudson/tasks/junit/TestObject.java +++ b/src/main/java/hudson/tasks/junit/TestObject.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Tom Huybrechts, Yahoo! Inc., InfraDNA, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -40,16 +40,17 @@ * * @deprecated * Use {@link hudson.tasks.test.TestObject} instead. - * + * * @author Kohsuke Kawaguchi */ +@Deprecated @ExportedBean public abstract class TestObject extends AbstractModelObject implements Serializable { @Deprecated - public AbstractBuild getOwner() { + public AbstractBuild getOwner() { if (Util.isOverridden(TestObject.class, getClass(), "getRun")) { - Run r = getRun(); + Run r = getRun(); return r instanceof AbstractBuild ? (AbstractBuild) r : null; } else { throw new AbstractMethodError("you must override getRun"); @@ -60,13 +61,13 @@ public AbstractBuild getOwner() { * @return the run in which this test was executed. * @since 1.2-beta-1 */ - public Run getRun() { + public Run getRun() { return getOwner(); } - + public abstract TestObject getParent(); - public abstract String getId(); + public abstract String getId(); /** * Returns the URL of this {@link TestObject}, relative to the context root. @@ -74,25 +75,25 @@ public Run getRun() { * @return * String like "job/foo/32/testReport/junit/com.company/Class" with no trailing or leading slash. */ - public abstract String getUrl(); + public abstract String getUrl(); - public abstract TestResult getTestResult(); + public abstract TestResult getTestResult(); - public abstract AbstractTestResultAction getTestResultAction(); + public abstract AbstractTestResultAction getTestResultAction(); - public abstract List getTestActions(); + public abstract List getTestActions(); public abstract T getTestAction(Class klazz); /** - * Gets the counter part of this {@link TestObject} in the previous run. - * - * @return null if no such counter part exists. - */ - public abstract TestObject getPreviousResult(); + * Gets the counter part of this {@link TestObject} in the previous run. + * + * @return null if no such counter part exists. + */ + public abstract TestObject getPreviousResult(); @Deprecated - public TestObject getResultInBuild(AbstractBuild build) { + public TestObject getResultInBuild(AbstractBuild build) { if (Util.isOverridden(TestObject.class, getClass(), "getResultInRun", Run.class)) { return getResultInRun(build); } else { @@ -106,7 +107,7 @@ public TestObject getResultInBuild(AbstractBuild build) { * @return the test result for the provided run. * @since 1.2-beta-1 */ - public TestObject getResultInRun(Run run) { + public TestObject getResultInRun(Run run) { if (run instanceof AbstractBuild) { return getResultInBuild((AbstractBuild) run); } else { @@ -114,45 +115,45 @@ public TestObject getResultInRun(Run run) { } } - /** - * Time took to run this test. In seconds. + /** + * Time took to run this test. In seconds. * * @return the time in seconds the test ran. - */ - public abstract float getDuration(); + */ + public abstract float getDuration(); - /** - * Returns the string representation of the {@link #getDuration()}, in a - * human readable format. + /** + * Returns the string representation of the {@link #getDuration()}, in a + * human readable format. * * @return a string representation of {@link #getDuration()}. - */ - public abstract String getDurationString(); + */ + public abstract String getDurationString(); public abstract String getDescription(); public abstract void setDescription(String description); /** - * Exposes this object through the remote API. + * Exposes this object through the remote API. * * @return the api for this test object. - */ - public abstract Api getApi(); + */ + public abstract Api getApi(); /** - * Gets the name of this object. + * Gets the name of this object. * * @return the name of this object. - */ - public abstract String getName(); + */ + public abstract String getName(); /** - * Gets the version of {@link #getName()} that's URL-safe. + * Gets the version of {@link #getName()} that's URL-safe. * * @return the URL-safe name of this object. - */ - public abstract String getSafeName(); + */ + public abstract String getSafeName(); @Override public abstract String getSearchUrl(); @@ -187,11 +188,11 @@ public TestObject getResultInRun(Run run) { public abstract History getHistory(); -// public abstract Object getDynamic(String token, StaplerRequest req, -// StaplerResponse rsp); -// -// public abstract HttpResponse doSubmitDescription( -// @QueryParameter String description) throws IOException, -// ServletException; + // public abstract Object getDynamic(String token, StaplerRequest req, + // StaplerResponse rsp); + // + // public abstract HttpResponse doSubmitDescription( + // @QueryParameter String description) throws IOException, + // ServletException; } diff --git a/src/main/java/hudson/tasks/junit/TestResult.java b/src/main/java/hudson/tasks/junit/TestResult.java index 8ed48fa5..3ab1c7db 100644 --- a/src/main/java/hudson/tasks/junit/TestResult.java +++ b/src/main/java/hudson/tasks/junit/TestResult.java @@ -71,10 +71,11 @@ */ public final class TestResult extends MetaTabulatedResult { - private static final Logger LOGGER = Logger.getLogger(JUnitResultArchiver.class.getName()); - @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "We do not expect TestResult to be serialized when this field is set.") + @SuppressFBWarnings( + value = "SE_BAD_FIELD", + justification = "We do not expect TestResult to be serialized when this field is set.") private final @CheckForNull TestResultImpl impl; /** @@ -91,12 +92,12 @@ public final class TestResult extends MetaTabulatedResult { /** * {@link #suites} keyed by their node ID for faster lookup. May be empty. */ - private transient Map> suitesByNode; + private transient Map> suitesByNode; /** * Results tabulated by package. */ - private transient Map byPackages; + private transient Map byPackages; // set during the freeze phase private transient AbstractTestResultAction parentAction; @@ -117,7 +118,7 @@ public final class TestResult extends MetaTabulatedResult { private float duration; private boolean skipOldReports; - + private long startTime = -1; /** @@ -131,7 +132,8 @@ public final class TestResult extends MetaTabulatedResult { private boolean keepProperties; // default 3s as it depends on OS some can be good some not really.... - public static final long FILE_TIME_PRECISION_MARGIN = Long.getLong(TestResult.class.getName() + "filetime.precision.margin", 3000); + public static final long FILE_TIME_PRECISION_MARGIN = + Long.getLong(TestResult.class.getName() + "filetime.precision.margin", 3000); /** * Creates an empty result. @@ -171,8 +173,12 @@ public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLon } @Deprecated - public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLongStdio, - PipelineTestDetails pipelineTestDetails) throws IOException { + public TestResult( + long filesTimestamp, + DirectoryScanner results, + boolean keepLongStdio, + PipelineTestDetails pipelineTestDetails) + throws IOException { this.stdioRetention = StdioRetention.fromKeepLongStdio(keepLongStdio); this.keepProperties = false; impl = null; @@ -188,15 +194,42 @@ public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLon * @since 1.22 */ @Deprecated - public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLongStdio, boolean keepProperties, - PipelineTestDetails pipelineTestDetails, boolean skipOldReports) throws IOException { - this(filesTimestamp, results, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, false, pipelineTestDetails, skipOldReports); + public TestResult( + long filesTimestamp, + DirectoryScanner results, + boolean keepLongStdio, + boolean keepProperties, + PipelineTestDetails pipelineTestDetails, + boolean skipOldReports) + throws IOException { + this( + filesTimestamp, + results, + StdioRetention.fromKeepLongStdio(keepLongStdio), + keepProperties, + false, + pipelineTestDetails, + skipOldReports); } @Deprecated - public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLongStdio, boolean keepProperties, boolean keepTestNames, - PipelineTestDetails pipelineTestDetails, boolean skipOldReports) throws IOException { - this(filesTimestamp, results, StdioRetention.fromKeepLongStdio(keepLongStdio), keepProperties, keepTestNames, pipelineTestDetails, skipOldReports); + public TestResult( + long filesTimestamp, + DirectoryScanner results, + boolean keepLongStdio, + boolean keepProperties, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails, + boolean skipOldReports) + throws IOException { + this( + filesTimestamp, + results, + StdioRetention.fromKeepLongStdio(keepLongStdio), + keepProperties, + keepTestNames, + pipelineTestDetails, + skipOldReports); } /** @@ -209,8 +242,15 @@ public TestResult(long filesTimestamp, DirectoryScanner results, boolean keepLon * @param pipelineTestDetails A {@link PipelineTestDetails} instance containing Pipeline-related additional arguments. * @param skipOldReports to parse or not test files older than filesTimestamp */ - public TestResult(long filesTimestamp, DirectoryScanner results, StdioRetention stdioRetention, boolean keepProperties, boolean keepTestNames, - PipelineTestDetails pipelineTestDetails, boolean skipOldReports) throws IOException { + public TestResult( + long filesTimestamp, + DirectoryScanner results, + StdioRetention stdioRetention, + boolean keepProperties, + boolean keepTestNames, + PipelineTestDetails pipelineTestDetails, + boolean skipOldReports) + throws IOException { this.stdioRetention = stdioRetention; this.keepProperties = keepProperties; this.keepTestNames = keepTestNames; @@ -233,7 +273,7 @@ public TestResultImpl getPluggableStorage() { @Override public TestObject getParent() { - return parent; + return parent; } @Override @@ -243,7 +283,7 @@ public void setParent(TestObject parent) { @Override public TestResult getTestResult() { - return this; + return this; } public TestResult(TestResult src) { @@ -263,9 +303,10 @@ public TestResult(TestResult src) { } static final XMLInputFactory xmlFactory; + static { - xmlFactory = XMLInputFactory.newInstance(); - if (SystemProperties.getBoolean(TestResult.class.getName() + ".USE_SAFE_XML_FACTORY", true)) { + xmlFactory = XMLInputFactory.newInstance(); + if (SystemProperties.getBoolean(TestResult.class.getName() + ".USE_SAFE_XML_FACTORY", true)) { xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); xmlFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE); } @@ -276,12 +317,12 @@ public static XMLInputFactory getXmlFactory() { } public void parse(XmlFile f) throws XMLStreamException, IOException { - try (Reader r = f.readRaw()){ + try (Reader r = f.readRaw()) { final XMLStreamReader reader = getXmlFactory().createXMLStreamReader(r); while (reader.hasNext()) { final int event = reader.next(); - if (event == XMLStreamReader.START_ELEMENT && reader.getName() - .getLocalPart().equals("result")) { + if (event == XMLStreamReader.START_ELEMENT + && reader.getName().getLocalPart().equals("result")) { parseXmlResult(reader); } } @@ -306,7 +347,8 @@ private void parseXmlResult(final XMLStreamReader reader) throws XMLStreamExcept duration = CaseResult.clampDuration(new TimeToFloat(reader.getElementText()).parse()); break; case "keepLongStdio": - stdioRetention = StdioRetention.fromKeepLongStdio(Boolean.parseBoolean(reader.getElementText())); + stdioRetention = + StdioRetention.fromKeepLongStdio(Boolean.parseBoolean(reader.getElementText())); break; case "stdioRetention": stdioRetention = StdioRetention.parse(reader.getElementText()); @@ -368,15 +410,15 @@ public void parse(long filesTimestamp, DirectoryScanner results) throws IOExcept * @throws IOException if an error occurs. * @since 1.22 */ - public void parse(long filesTimestamp, DirectoryScanner results, PipelineTestDetails pipelineTestDetails) throws IOException { + public void parse(long filesTimestamp, DirectoryScanner results, PipelineTestDetails pipelineTestDetails) + throws IOException { String[] includedFiles = results.getIncludedFiles(); File baseDir = results.getBasedir(); - parse(filesTimestamp,baseDir, pipelineTestDetails,includedFiles); + parse(filesTimestamp, baseDir, pipelineTestDetails, includedFiles); } @Deprecated - public void parse(long filesTimestamp, File baseDir, String[] reportFiles) - throws IOException { + public void parse(long filesTimestamp, File baseDir, String[] reportFiles) throws IOException { parse(filesTimestamp, baseDir, null, reportFiles); } @@ -391,25 +433,33 @@ public void parse(long filesTimestamp, File baseDir, String[] reportFiles) * @throws IOException if an error occurs. * @since 1.22 */ - public void parse(long filesTimestamp, File baseDir, PipelineTestDetails pipelineTestDetails, String[] reportFiles) throws IOException { - List files = Arrays.stream(reportFiles).map(s -> new File(baseDir, s)).collect(Collectors.toList()); + public void parse(long filesTimestamp, File baseDir, PipelineTestDetails pipelineTestDetails, String[] reportFiles) + throws IOException { + List files = + Arrays.stream(reportFiles).map(s -> new File(baseDir, s)).collect(Collectors.toList()); parse(filesTimestamp, pipelineTestDetails, files); - } - private void parse(long filesTimestamp, PipelineTestDetails pipelineTestDetails, Iterable reportFiles) throws IOException { + private void parse(long filesTimestamp, PipelineTestDetails pipelineTestDetails, Iterable reportFiles) + throws IOException { for (File reportFile : reportFiles) { - if(skipOldReports && Files.getLastModifiedTime(reportFile.toPath()).toMillis() < filesTimestamp - FILE_TIME_PRECISION_MARGIN ) { + if (skipOldReports + && Files.getLastModifiedTime(reportFile.toPath()).toMillis() + < filesTimestamp - FILE_TIME_PRECISION_MARGIN) { if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("file " + reportFile + " not parsed: skipOldReports-" + skipOldReports - + ",lastModified:" + Files.getLastModifiedTime(reportFile.toPath()).toMillis() + ",filesTimestamp:" + filesTimestamp); + LOGGER.fine( + "file " + reportFile + " not parsed: skipOldReports-" + skipOldReports + ",lastModified:" + + Files.getLastModifiedTime(reportFile.toPath()) + .toMillis() + ",filesTimestamp:" + filesTimestamp); } continue; } // only count files that were actually updated during this build parsePossiblyEmpty(reportFile, pipelineTestDetails); } - if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("testSuites size:" + this.getSuites().size()); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("testSuites size:" + this.getSuites().size()); + } } @Override @@ -417,7 +467,7 @@ public hudson.tasks.test.TestResult getPreviousResult() { if (impl != null) { return impl.getPreviousResult(); } - + return super.getPreviousResult(); } @@ -436,7 +486,8 @@ public void parse(long filesTimestamp, Iterable reportFiles) throws IOExce * @throws IOException if an error occurs. * @since 1.22 */ - public void parse(long filesTimestamp, Iterable reportFiles, PipelineTestDetails pipelineTestDetails) throws IOException { + public void parse(long filesTimestamp, Iterable reportFiles, PipelineTestDetails pipelineTestDetails) + throws IOException { parse(filesTimestamp, pipelineTestDetails, reportFiles); } @@ -458,34 +509,37 @@ public void parse(Iterable reportFiles, PipelineTestDetails pipelineTestDe } private void parsePossiblyEmpty(File reportFile, PipelineTestDetails pipelineTestDetails) throws IOException { - if(reportFile.length()==0) { - if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("reportFile:" + reportFile + " is empty"); + if (reportFile.length() == 0) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("reportFile:" + reportFile + " is empty"); + } // this is a typical problem when JVM quits abnormally, like OutOfMemoryError during a test. SuiteResult sr = new SuiteResult(reportFile.getName(), "", "", pipelineTestDetails); - sr.addCase(new CaseResult(sr,"[empty]","Test report file "+reportFile.getAbsolutePath()+" was length 0")); + sr.addCase(new CaseResult( + sr, "[empty]", "Test report file " + reportFile.getAbsolutePath() + " was length 0")); add(sr); } else { parse(reportFile, pipelineTestDetails); } } - + private void add(SuiteResult sr) { - long suiteStart = sr.getStartTime(); + long suiteStart = sr.getStartTime(); for (SuiteResult s : suites) { // JENKINS-12457: If a testsuite is distributed over multiple files, merge it into a single SuiteResult: - if(s.getName().equals(sr.getName()) && - eitherNullOrEq(s.getId(),sr.getId()) && - nullSafeEq(s.getNodeId(),sr.getNodeId()) && - nullSafeEq(s.getEnclosingBlocks(),sr.getEnclosingBlocks()) && - nullSafeEq(s.getEnclosingBlockNames(),sr.getEnclosingBlockNames())) { + if (s.getName().equals(sr.getName()) + && eitherNullOrEq(s.getId(), sr.getId()) + && nullSafeEq(s.getNodeId(), sr.getNodeId()) + && nullSafeEq(s.getEnclosingBlocks(), sr.getEnclosingBlocks()) + && nullSafeEq(s.getEnclosingBlockNames(), sr.getEnclosingBlockNames())) { // Set start time to earliest set start of a suite if (startTime == -1) { startTime = suiteStart; - } else if (suiteStart != -1){ + } else if (suiteStart != -1) { startTime = Math.min(startTime, suiteStart); } - + duration += sr.getDuration(); s.merge(sr); return; @@ -495,10 +549,10 @@ private void add(SuiteResult sr) { // Set start time to earliest set start of a suite if (startTime == -1) { startTime = suiteStart; - } else if (suiteStart != -1){ + } else if (suiteStart != -1) { startTime = Math.min(startTime, suiteStart); } - + suites.add(sr); duration += sr.getDuration(); } @@ -513,7 +567,7 @@ void merge(TestResult other) { } tally(); } - + private boolean strictEq(Object lhs, Object rhs) { return lhs != null && rhs != null && lhs.equals(rhs); } @@ -550,26 +604,32 @@ public void parse(File reportFile, PipelineTestDetails pipelineTestDetails) thro throw new IllegalStateException("Cannot reparse using a pluggable impl"); } try { - List suiteResults = SuiteResult.parse(reportFile, stdioRetention, keepProperties, keepTestNames, pipelineTestDetails); - for (SuiteResult suiteResult : suiteResults) + List suiteResults = + SuiteResult.parse(reportFile, stdioRetention, keepProperties, keepTestNames, pipelineTestDetails); + for (SuiteResult suiteResult : suiteResults) { add(suiteResult); + } if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("reportFile:" + reportFile + ", lastModified:" + reportFile.lastModified() + " found " + suiteResults.size() + " suite results" ); + LOGGER.fine("reportFile:" + reportFile + ", lastModified:" + reportFile.lastModified() + " found " + + suiteResults.size() + " suite results"); } } catch (InterruptedException | RuntimeException e) { - throw new IOException("Failed to read "+reportFile,e); + throw new IOException("Failed to read " + reportFile, e); } catch (DocumentException e) { if (!reportFile.getPath().endsWith(".xml")) { - throw new IOException("Failed to read "+reportFile+"\n"+ - "Is this really a JUnit report file? Your configuration must be matching too many files",e); + throw new IOException( + "Failed to read " + reportFile + "\n" + + "Is this really a JUnit report file? Your configuration must be matching too many files", + e); } else { SuiteResult sr = new SuiteResult(reportFile.getName(), "", "", null); StringWriter writer = new StringWriter(); e.printStackTrace(new PrintWriter(writer)); - String error = "Failed to read test report file "+reportFile.getAbsolutePath()+"\n"+writer.toString(); - sr.addCase(new CaseResult(sr,"[failed-to-read]",error)); + String error = + "Failed to read test report file " + reportFile.getAbsolutePath() + "\n" + writer.toString(); + sr.addCase(new CaseResult(sr, "[failed-to-read]", error)); add(sr); } } @@ -581,14 +641,14 @@ public String getDisplayName() { } @Override - public Run getRun() { + public Run getRun() { if (parentAction != null) { return parentAction.run; } if (impl == null) { return null; } - + return impl.getRun(); } @@ -635,7 +695,7 @@ public hudson.tasks.test.TestResult findCorrespondingResult(String id) { } } else { return null; - } + } } @Override @@ -653,16 +713,16 @@ public String getChildType() { return "package"; } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public float getDuration() { if (impl != null) { return impl.getTotalTestDuration(); } - + return duration; } - + public void setStartTime(long start) { startTime = start; } @@ -671,29 +731,29 @@ public long getStartTime() { return startTime; } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public int getPassCount() { if (impl != null) { return impl.getPassCount(); } - return totalTests-getFailCount()-getSkipCount(); + return totalTests - getFailCount() - getSkipCount(); } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public int getFailCount() { if (impl != null) { return impl.getFailCount(); } - if(failedTests==null) { + if (failedTests == null) { return 0; } else { return failedTests.size(); } } - @Exported(visibility=999) + @Exported(visibility = 999) @Override public int getSkipCount() { if (impl != null) { @@ -709,14 +769,14 @@ public int getTotalCount() { } return super.getTotalCount(); } - + /** * Returns true if this doesn't have any any test results. * * @return whether this doesn't contain any test results. * @since 1.511 */ - @Exported(visibility=999) + @Exported(visibility = 999) public boolean isEmpty() { return getTotalCount() == 0; } @@ -739,11 +799,11 @@ public synchronized List getPassedTests() { if (impl != null) { return impl.getPassedTests(); } - - if(passedTests == null){ + + if (passedTests == null) { passedTests = new ArrayList<>(); - for(SuiteResult s : suites) { - for(CaseResult cr : s.getCases()) { + for (SuiteResult s : suites) { + for (CaseResult cr : s.getCases()) { if (cr.isPassed()) { passedTests.add(cr); } @@ -764,11 +824,11 @@ public synchronized List getSkippedTests() { if (impl != null) { return impl.getSkippedTests(); } - - if(skippedTests == null){ + + if (skippedTests == null) { skippedTests = new ArrayList<>(); - for(SuiteResult s : suites) { - for(CaseResult cr : s.getCases()) { + for (SuiteResult s : suites) { + for (CaseResult cr : s.getCases()) { if (cr.isSkipped()) { skippedTests.add(cr); } @@ -785,7 +845,7 @@ public synchronized List getSkippedTests() { */ @Override public int getFailedSince() { - throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated) + throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated) } /** @@ -794,7 +854,7 @@ public int getFailedSince() { */ @Override public Run getFailedSinceRun() { - throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated) + throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated) } /** @@ -812,7 +872,7 @@ public int getFailedSince() { @Override public String getStdout() { StringBuilder sb = new StringBuilder(); - for (SuiteResult suite: suites) { + for (SuiteResult suite : suites) { sb.append("Standard Out (stdout) for Suite: " + suite.getName()); sb.append(suite.getStdout()); } @@ -828,7 +888,7 @@ public String getStdout() { @Override public String getStderr() { StringBuilder sb = new StringBuilder(); - for (SuiteResult suite: suites) { + for (SuiteResult suite : suites) { sb.append("Standard Error (stderr) for Suite: " + suite.getName()); sb.append(suite.getStderr()); } @@ -861,7 +921,7 @@ public String getErrorDetails() { */ @Override public boolean isPassed() { - return getFailCount() == 0; + return getFailCount() == 0; } @Override @@ -869,7 +929,7 @@ public Collection getChildren() { if (impl != null) { return impl.getAllPackageResults(); } - + return byPackages.values(); } @@ -881,7 +941,7 @@ public boolean hasChildren() { return !suites.isEmpty(); } - @Exported(inline=true,visibility=9) + @Exported(inline = true, visibility = 9) public Collection getSuites() { if (impl != null) { return impl.getSuites(); @@ -889,7 +949,6 @@ public Collection getSuites() { return suites; } - @Override public String getName() { return "junit"; @@ -903,9 +962,9 @@ public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) PackageResult result = byPackage(token); if (result != null) { - return result; + return result; } else { - return super.getDynamic(token, req, rsp); + return super.getDynamic(token, req, rsp); } } @@ -913,7 +972,7 @@ public PackageResult byPackage(String packageName) { if (impl != null) { return impl.getPackageResult(packageName); } - + return byPackages.get(packageName); } @@ -969,16 +1028,16 @@ public TestResult getResultByNodes(@NonNull List nodeIds) { return result; } - @Override - public void setParentAction(AbstractTestResultAction action) { + @Override + public void setParentAction(AbstractTestResultAction action) { this.parentAction = action; tally(); // I want to be sure to inform our children when we get an action. - } + } - @Override - public AbstractTestResultAction getParentAction() { - return this.parentAction; - } + @Override + public AbstractTestResultAction getParentAction() { + return this.parentAction; + } /** * Recount my children. @@ -1002,25 +1061,27 @@ public void tally() { // Ask all of our children to tally themselves for (SuiteResult s : suites) { s.setParent(this); // kluge to prevent double-counting the results - suitesByName.merge(s.getName(), Collections.singleton(s), (a,b) -> Stream.concat(a.stream(), b.stream()).collect(Collectors.toList())); + suitesByName.merge(s.getName(), Collections.singleton(s), (a, b) -> Stream.concat(a.stream(), b.stream()) + .collect(Collectors.toList())); if (s.getNodeId() != null) { addSuiteByNode(s); } List cases = s.getCases(); - for (CaseResult cr: cases) { + for (CaseResult cr : cases) { cr.setParentAction(this.parentAction); cr.setParentSuiteResult(s); cr.tally(); - String pkg = cr.getPackageName(), spkg = safe(pkg); + String pkg = cr.getPackageName(), spkg = safe(pkg); PackageResult pr = byPackage(spkg); - if(pr==null) - byPackages.put(spkg,pr=new PackageResult(this,pkg)); - + if (pr == null) { + byPackages.put(spkg, pr = new PackageResult(this, pkg)); + } + if (pr.getStartTime() == -1) { pr.setStartTime(s.getStartTime()); - } else if (s.getStartTime() != -1){ + } else if (s.getStartTime() != -1) { pr.setStartTime(Math.min(pr.getStartTime(), s.getStartTime())); } pr.add(cr); @@ -1046,7 +1107,7 @@ public void tally() { public void freeze(TestResultAction parent) { assert impl == null; this.parentAction = parent; - if(suitesByName==null) { + if (suitesByName == null) { // freeze for the first time suitesByName = new HashMap<>(); suitesByNode = new HashMap<>(); @@ -1059,38 +1120,41 @@ public void freeze(TestResultAction parent) { } for (SuiteResult s : suites) { - if(!s.freeze(this)) // this is disturbing: has-a-parent is conflated with has-been-counted + if (!s.freeze(this)) { // this is disturbing: has-a-parent is conflated with has-been-counted continue; + } - suitesByName.merge(s.getName(), Collections.singleton(s), (a,b) -> Stream.concat(a.stream(), b.stream()).collect(Collectors.toList())); + suitesByName.merge(s.getName(), Collections.singleton(s), (a, b) -> Stream.concat(a.stream(), b.stream()) + .collect(Collectors.toList())); if (s.getNodeId() != null) { addSuiteByNode(s); } totalTests += s.getCases().size(); - for(CaseResult cr : s.getCases()) { - if(cr.isSkipped()) { + for (CaseResult cr : s.getCases()) { + if (cr.isSkipped()) { skippedTestsCounter++; if (skippedTests != null) { skippedTests.add(cr); } - } else if(!cr.isPassed()) { + } else if (!cr.isPassed()) { failedTests.add(cr); } else { - if(passedTests != null) { + if (passedTests != null) { passedTests.add(cr); } } String pkg = cr.getPackageName(), spkg = safe(pkg); PackageResult pr = byPackage(spkg); - if(pr==null) - byPackages.put(spkg,pr=new PackageResult(this,pkg)); - + if (pr == null) { + byPackages.put(spkg, pr = new PackageResult(this, pkg)); + } + if (pr.getStartTime() == -1) { pr.setStartTime(s.getStartTime()); - } else if (s.getStartTime() != -1){ + } else if (s.getStartTime() != -1) { pr.setStartTime(Math.min(pr.getStartTime(), s.getStartTime())); } pr.add(cr); @@ -1099,16 +1163,17 @@ public void freeze(TestResultAction parent) { failedTests.sort(CaseResult.BY_AGE); - if(passedTests != null) { + if (passedTests != null) { passedTests.sort(CaseResult.BY_AGE); } - if(skippedTests != null) { + if (skippedTests != null) { skippedTests.sort(CaseResult.BY_AGE); } - for (PackageResult pr : byPackages.values()) + for (PackageResult pr : byPackages.values()) { pr.freeze(); + } } private void addSuiteByNode(SuiteResult s) { @@ -1133,7 +1198,7 @@ private void addSuiteByNode(SuiteResult s) { public TestResult getResultForPipelineBlock(@NonNull String blockId) { PipelineBlockWithTests block = getPipelineBlockWithTests(blockId); if (block != null) { - return (TestResult)blockToTestResult(block, this); + return (TestResult) blockToTestResult(block, this); } else { return this; } @@ -1152,7 +1217,8 @@ public void setSkipOldReports(boolean skipOldReports) { */ @Override @NonNull - public TabulatedResult blockToTestResult(@NonNull PipelineBlockWithTests block, @NonNull TabulatedResult fullResult) { + public TabulatedResult blockToTestResult( + @NonNull PipelineBlockWithTests block, @NonNull TabulatedResult fullResult) { TestResult result = new TestResult(); for (PipelineBlockWithTests child : block.getChildBlocks().values()) { TabulatedResult childResult = blockToTestResult(child, fullResult); @@ -1173,17 +1239,13 @@ public TabulatedResult blockToTestResult(@NonNull PipelineBlockWithTests block, return result; } - - private static final long serialVersionUID = 1L; public CaseResult getCase(String suiteName, String transformedFullDisplayName) { - return getSuites(suiteName) - .stream() + return getSuites(suiteName).stream() .map(suite -> suite.getCase(transformedFullDisplayName)) .filter(Objects::nonNull) .findFirst() .orElse(null); } - } diff --git a/src/main/java/hudson/tasks/junit/TestResultAction.java b/src/main/java/hudson/tasks/junit/TestResultAction.java index ddcb1ad5..ff87ab02 100644 --- a/src/main/java/hudson/tasks/junit/TestResultAction.java +++ b/src/main/java/hudson/tasks/junit/TestResultAction.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Red Hat, Inc., Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -67,12 +67,14 @@ * @author Kohsuke Kawaguchi */ @SuppressFBWarnings(value = "UG_SYNC_SET_UNSYNC_GET", justification = "False positive") -public class TestResultAction extends AbstractTestResultAction implements StaplerProxy, SimpleBuildStep.LastBuildAction { +public class TestResultAction extends AbstractTestResultAction + implements StaplerProxy, SimpleBuildStep.LastBuildAction { private static final Logger LOGGER = Logger.getLogger(TestResultAction.class.getName()); private transient WeakReference result; /** null only if there is a {@link JunitTestResultStorage} */ private @Nullable Integer failCount; + private @Nullable Integer skipCount; // Hudson < 1.25 didn't set these fields, so use Integer // so that we can distinguish between 0 tests vs not-computed-yet. @@ -101,9 +103,13 @@ public TestResultAction(TestResult result, BuildListener listener) { } @SuppressWarnings("deprecation") - @Override public Collection getProjectActions() { - Job job = run.getParent(); - if (/* getAction(Class) produces a StackOverflowError */!Util.filter(job.getActions(), TestResultProjectAction.class).isEmpty()) { + @Override + public Collection getProjectActions() { + Job job = run.getParent(); + if ( + /* getAction(Class) produces a StackOverflowError */ !Util.filter( + job.getActions(), TestResultProjectAction.class) + .isEmpty()) { // JENKINS-26077: someone like XUnitPublisher already added one return Collections.emptySet(); } @@ -123,13 +129,13 @@ public synchronized void setResult(TestResult result, TaskListener listener) { skipCount = result.getSkipCount(); if (run != null) { - // persist the data - try { - resultCache.put(getDataFilePath(), new SoftReference(result)); - getDataFile().write(result); - } catch (IOException e) { - e.printStackTrace(listener.fatalError("Failed to save the JUnit test result")); - } + // persist the data + try { + resultCache.put(getDataFilePath(), new SoftReference(result)); + getDataFile().write(result); + } catch (IOException e) { + e.printStackTrace(listener.fatalError("Failed to save the JUnit test result")); + } } this.result = new WeakReference<>(result); @@ -156,18 +162,18 @@ public synchronized TestResult getResult() { return new TestResult(storage.load(run.getParent().getFullName(), run.getNumber())); } TestResult r; - if (result==null) { + if (result == null) { r = load(); result = new WeakReference<>(r); } else { r = result.get(); } - if(r==null) { + if (r == null) { r = load(); result = new WeakReference<>(r); } - if(totalCount==null) { + if (totalCount == null) { totalCount = r.getTotalCount(); failCount = r.getFailCount(); skipCount = r.getSkipCount(); @@ -185,8 +191,9 @@ public synchronized int getFailCount() { if (!(storage instanceof FileJunitTestResultStorage)) { return new TestResult(storage.load(run.getParent().getFullName(), run.getNumber())).getFailCount(); } - if(totalCount==null) - getResult(); // this will compute the result + if (totalCount == null) { + getResult(); // this will compute the result + } return failCount; } @@ -196,8 +203,9 @@ public synchronized int getSkipCount() { if (!(storage instanceof FileJunitTestResultStorage)) { return new TestResult(storage.load(run.getParent().getFullName(), run.getNumber())).getSkipCount(); } - if(totalCount==null) - getResult(); // this will compute the result + if (totalCount == null) { + getResult(); // this will compute the result + } return skipCount; } @@ -207,8 +215,9 @@ public synchronized int getTotalCount() { if (!(storage instanceof FileJunitTestResultStorage)) { return new TestResult(storage.load(run.getParent().getFullName(), run.getNumber())).getTotalCount(); } - if(totalCount==null) - getResult(); // this will compute the result + if (totalCount == null) { + getResult(); // this will compute the result + } return totalCount; } @@ -218,14 +227,14 @@ public double getHealthScaleFactor() { } public void setHealthScaleFactor(double healthScaleFactor) { - this.healthScaleFactor = Math.max(0.0,healthScaleFactor); + this.healthScaleFactor = Math.max(0.0, healthScaleFactor); } @Override - public List getFailedTests() { + public List getFailedTests() { TestResult result = getResult(); return result.getFailedTests(); - } + } @Override public List getPassedTests() { @@ -245,7 +254,7 @@ private TestResult parseOnly() { r.parse(df); } catch (Exception e) { logger.log(Level.WARNING, "Failed to load " + df, e); - r = new TestResult(); // return a dummy + r = new TestResult(); // return a dummy } return r; } @@ -255,11 +264,12 @@ private TestResult parseOnly() { static long lastCleanupNs = 0; static long LARGE_RESULT_CACHE_CLEANUP_INTERVAL_NS = - SystemProperties.getLong(TestResultAction.class.getName() + ".LARGE_RESULT_CACHE_CLEANUP_INTERVAL_MS",500L) * 1000000L; + SystemProperties.getLong(TestResultAction.class.getName() + ".LARGE_RESULT_CACHE_CLEANUP_INTERVAL_MS", 500L) + * 1000000L; static int LARGE_RESULT_CACHE_THRESHOLD = - SystemProperties.getInteger(TestResultAction.class.getName() + ".LARGE_RESULT_CACHE_THRESHOLD",1000); + SystemProperties.getInteger(TestResultAction.class.getName() + ".LARGE_RESULT_CACHE_THRESHOLD", 1000); static boolean RESULT_CACHE_ENABLED = - SystemProperties.getBoolean(TestResultAction.class.getName() + ".RESULT_CACHE_ENABLED",true); + SystemProperties.getBoolean(TestResultAction.class.getName() + ".RESULT_CACHE_ENABLED", true); /** * Loads a {@link TestResult} from cache or disk. @@ -277,10 +287,10 @@ private TestResult load() { private TestResult loadFallback() { TestResult r; try { - r = (TestResult)getDataFile().read(); + r = (TestResult) getDataFile().read(); } catch (IOException e) { - logger.log(Level.WARNING, "Failed to load "+getDataFile(),e); - r = new TestResult(); // return a dummy + logger.log(Level.WARNING, "Failed to load " + getDataFile(), e); + r = new TestResult(); // return a dummy } r.freeze(this); return r; @@ -291,9 +301,9 @@ private TestResult loadFallback() { */ private TestResult loadCached() { if (resultCache.size() > LARGE_RESULT_CACHE_THRESHOLD) { - synchronized (syncObj) - { - if (resultCache.size() > LARGE_RESULT_CACHE_THRESHOLD && (System.nanoTime() - lastCleanupNs) > LARGE_RESULT_CACHE_CLEANUP_INTERVAL_NS) { + synchronized (syncObj) { + if (resultCache.size() > LARGE_RESULT_CACHE_THRESHOLD + && (System.nanoTime() - lastCleanupNs) > LARGE_RESULT_CACHE_CLEANUP_INTERVAL_NS) { lastCleanupNs = System.nanoTime(); resultCache.forEach((String k, SoftReference v) -> { if (v.get() == null) { @@ -305,9 +315,9 @@ private TestResult loadCached() { } TestResult r; String k = getDataFilePath(); - r = resultCache.computeIfAbsent(k, path -> { - return new SoftReference(parseOnly()); - }).get(); + r = resultCache + .computeIfAbsent(k, path -> new SoftReference(parseOnly())) + .get(); if (r == null) { r = parseOnly(); resultCache.replace(k, new SoftReference(r)); @@ -327,10 +337,13 @@ public List getActions(TestObject object) { // Added check for null testData to avoid NPE from issue 4257. if (testData != null) { synchronized (testData) { - for (Data data : testData) - for (TestAction ta : data.getTestAction(object)) - if (ta != null) + for (Data data : testData) { + for (TestAction ta : data.getTestAction(object)) { + if (ta != null) { result.add(ta); + } + } + } } } return Collections.unmodifiableList(result); @@ -348,7 +361,7 @@ List getData() { * */ public void setData(List testData) { - this.testData = testData; + this.testData = testData; } /** @@ -382,24 +395,24 @@ public void mergeResult(TestResult additionalResult, TaskListener listener) { * * @see TestDataPublisher */ - public static abstract class Data { - /** - * Returns all TestActions for the testObject. + public abstract static class Data { + /** + * Returns all TestActions for the testObject. * * @return * Can be empty but never null. The caller must assume that the returned list is read-only. - */ - public abstract List getTestAction(hudson.tasks.junit.TestObject testObject); + */ + public abstract List getTestAction(hudson.tasks.junit.TestObject testObject); } @Override public Object readResolve() { super.readResolve(); // let it do the post-deserialization work - if (testData == null) { - testData = new ArrayList<>(0); - } + if (testData == null) { + testData = new ArrayList<>(0); + } - return this; + return this; } private static final Logger logger = Logger.getLogger(TestResultAction.class.getName()); @@ -407,10 +420,9 @@ public Object readResolve() { static final XStream XSTREAM = new XStream2(); static { - XSTREAM.alias("result",TestResult.class); - XSTREAM.alias("suite",SuiteResult.class); - XSTREAM.alias("case",CaseResult.class); - XSTREAM.registerConverter(new HeapSpaceStringConverter(),100); + XSTREAM.alias("result", TestResult.class); + XSTREAM.alias("suite", SuiteResult.class); + XSTREAM.alias("case", CaseResult.class); + XSTREAM.registerConverter(new HeapSpaceStringConverter(), 100); } - } diff --git a/src/main/java/hudson/tasks/junit/TestResultSummary.java b/src/main/java/hudson/tasks/junit/TestResultSummary.java index 5c4af50f..049f900b 100644 --- a/src/main/java/hudson/tasks/junit/TestResultSummary.java +++ b/src/main/java/hudson/tasks/junit/TestResultSummary.java @@ -16,8 +16,7 @@ public class TestResultSummary implements Serializable { @Deprecated @Restricted(DoNotUse.class) - public TestResultSummary() { - } + public TestResultSummary() {} public TestResultSummary(int failCount, int skipCount, int passCount, int totalCount) { this.failCount = failCount; @@ -34,7 +33,8 @@ public TestResultSummary(TestResult result) { if (totalCount == 0) { for (SuiteResult suite : result.getSuites()) { if (!suite.getCases().isEmpty()) { - throw new IllegalArgumentException("Attempt to construct TestResultSummary from TestResult without calling tally/freeze"); + throw new IllegalArgumentException( + "Attempt to construct TestResultSummary from TestResult without calling tally/freeze"); } } } @@ -60,4 +60,3 @@ public int getTotalCount() { return totalCount; } } - diff --git a/src/main/java/hudson/tasks/junit/TrendTestResultSummary.java b/src/main/java/hudson/tasks/junit/TrendTestResultSummary.java index c914ca33..cd0192f2 100644 --- a/src/main/java/hudson/tasks/junit/TrendTestResultSummary.java +++ b/src/main/java/hudson/tasks/junit/TrendTestResultSummary.java @@ -6,7 +6,7 @@ import java.util.Map; public class TrendTestResultSummary implements Serializable { - + private int buildNumber; private TestResultSummary testResultSummary; @@ -30,7 +30,7 @@ public Map toMap() { public int getBuildNumber() { return buildNumber; } - + public String getDisplayName() { return "#" + buildNumber; } diff --git a/src/main/java/hudson/tasks/junit/XMLEntityResolver.java b/src/main/java/hudson/tasks/junit/XMLEntityResolver.java index 5e88787b..a9885be6 100644 --- a/src/main/java/hudson/tasks/junit/XMLEntityResolver.java +++ b/src/main/java/hudson/tasks/junit/XMLEntityResolver.java @@ -63,8 +63,9 @@ public InputSource resolveEntity(String publicId, String systemId) throws SAXExc String dtdFileName = systemId.substring(systemId.lastIndexOf("/") + 1); URL url = getClass().getClassLoader().getResource(dtdFileName); - if (url != null) + if (url != null) { return new InputSource(url.toString()); + } } } // Default fallback diff --git a/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStep.java b/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStep.java index 23524e4d..c721427b 100644 --- a/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStep.java +++ b/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStep.java @@ -59,6 +59,7 @@ public class JUnitResultsStep extends Step implements JUnitTask { * If true, don't throw exception on missing test results or no files found. */ private boolean allowEmptyResults; + private boolean skipPublishingChecks; private String checksName; /** @@ -104,7 +105,8 @@ public List getTestDataPublishers() { * * @since 1.2 */ - @DataBoundSetter public final void setTestDataPublishers(@NonNull List testDataPublishers) { + @DataBoundSetter + public final void setTestDataPublishers(@NonNull List testDataPublishers) { this.testDataPublishers = new DescribableList<>(Saveable.NOOP); this.testDataPublishers.addAll(testDataPublishers); } @@ -115,10 +117,12 @@ public List getTestDataPublishers() { * @since 1.2-beta-1 */ @Deprecated - @DataBoundSetter public final void setKeepLongStdio(boolean keepLongStdio) { + @DataBoundSetter + public final void setKeepLongStdio(boolean keepLongStdio) { this.stdioRetention = StdioRetention.fromKeepLongStdio(keepLongStdio).name(); } + @Override @Deprecated public boolean isKeepLongStdio() { return StdioRetention.ALL == getParsedStdioRetention(); @@ -135,7 +139,8 @@ public String getStdioRetention() { /** * @param stdioRetention How to keep long stdio. */ - @DataBoundSetter public final void setStdioRetention(String stdioRetention) { + @DataBoundSetter + public final void setStdioRetention(String stdioRetention) { this.stdioRetention = stdioRetention; } @@ -150,13 +155,15 @@ public boolean isKeepProperties() { /** * @param keepProperties Whether to keep the properties */ - @DataBoundSetter public final void setKeepProperties(boolean keepProperties) { + @DataBoundSetter + public final void setKeepProperties(boolean keepProperties) { this.keepProperties = keepProperties; } /** * @return the keepTestNames. */ + @Override public boolean isKeepTestNames() { return keepTestNames; } @@ -164,7 +171,8 @@ public boolean isKeepTestNames() { /** * @param keepTestNames Whether to avoid adding parallel stage name into test name. */ - @DataBoundSetter public final void setKeepTestNames(boolean keepTestNames) { + @DataBoundSetter + public final void setKeepTestNames(boolean keepTestNames) { this.keepTestNames = keepTestNames; } @@ -180,7 +188,7 @@ public boolean isAllowEmptyResults() { /** * Should we skip publishing checks to the checks API plugin. * - * @return if publishing checks should be skipped, {@code false} otherwise + * @return if publishing checks should be skipped, {@code false} otherwise */ @Override public boolean isSkipPublishingChecks() { @@ -202,7 +210,8 @@ public void setChecksName(String checksName) { this.checksName = checksName; } - @DataBoundSetter public final void setAllowEmptyResults(boolean allowEmptyResults) { + @DataBoundSetter + public final void setAllowEmptyResults(boolean allowEmptyResults) { this.allowEmptyResults = allowEmptyResults; } @@ -251,14 +260,12 @@ public Set> getRequiredContext() { } public FormValidation doCheckHealthScaleFactor(@QueryParameter double value) { - if (value < 1e-7) return FormValidation.warning("Test health reporting disabled"); + if (value < 1e-7) { + return FormValidation.warning("Test health reporting disabled"); + } return FormValidation.ok(Messages.JUnitResultArchiver_HealthScaleFactorAnalysis( - 1, - (int) (100.0 - Math.max(0.0, Math.min(100.0, 1 * value))), - 5, - (int) (100.0 - Math.max(0.0, Math.min(100.0, 5 * value))) - )); + 1, (int) (100.0 - Math.max(0.0, Math.min(100.0, 1 * value))), 5, (int) + (100.0 - Math.max(0.0, Math.min(100.0, 5 * value))))); } - } } diff --git a/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStepExecution.java b/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStepExecution.java index d03c397a..3f539afa 100644 --- a/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStepExecution.java +++ b/src/main/java/hudson/tasks/junit/pipeline/JUnitResultsStepExecution.java @@ -26,7 +26,7 @@ public class JUnitResultsStepExecution extends SynchronousNonBlockingStepExecution { - private transient final JUnitResultsStep step; + private final transient JUnitResultsStep step; public JUnitResultsStepExecution(@NonNull JUnitResultsStep step, StepContext context) { super(context); @@ -37,7 +37,7 @@ public JUnitResultsStepExecution(@NonNull JUnitResultsStep step, StepContext con protected TestResultSummary run() throws Exception { FilePath workspace = getContext().get(FilePath.class); workspace.mkdirs(); - Run run = Objects.requireNonNull(getContext().get(Run.class)); + Run run = Objects.requireNonNull(getContext().get(Run.class)); TaskListener listener = getContext().get(TaskListener.class); Launcher launcher = getContext().get(Launcher.class); FlowNode node = getContext().get(FlowNode.class); @@ -52,18 +52,21 @@ protected TestResultSummary run() throws Exception { pipelineTestDetails.setEnclosingBlockNames(getEnclosingBlockNames(enclosingBlocks)); try { - // If we are within a withChecks context, and have not provided a name override in the step, apply the withChecks name + // If we are within a withChecks context, and have not provided a name override in the step, apply the + // withChecks name if (Util.fixEmpty(step.getChecksName()) == null) { Optional.ofNullable(getContext().get(ChecksInfo.class)) .map(ChecksInfo::getName) .ifPresent(step::setChecksName); } - TestResultSummary summary = JUnitResultArchiver.parseAndSummarize(step, pipelineTestDetails, run, workspace, launcher, listener); + TestResultSummary summary = JUnitResultArchiver.parseAndSummarize( + step, pipelineTestDetails, run, workspace, launcher, listener); if (summary.getFailCount() > 0) { int testFailures = summary.getFailCount(); if (testFailures > 0) { - node.addOrReplaceAction(new WarningAction(Result.UNSTABLE).withMessage(testFailures + " tests failed")); + node.addOrReplaceAction( + new WarningAction(Result.UNSTABLE).withMessage(testFailures + " tests failed")); if (!step.isSkipMarkingBuildUnstable()) { run.setResult(Result.UNSTABLE); } @@ -87,8 +90,7 @@ public static List getEnclosingStagesAndParallels(FlowNode node) { List enclosingBlocks = new ArrayList<>(); for (FlowNode enclosing : node.getEnclosingBlocks()) { if (enclosing != null && enclosing.getAction(LabelAction.class) != null) { - if (isStageNode(enclosing) || - (enclosing.getAction(ThreadNameAction.class) != null)) { + if (isStageNode(enclosing) || (enclosing.getAction(ThreadNameAction.class) != null)) { enclosingBlocks.add(enclosing); } } @@ -124,7 +126,7 @@ public static List getEnclosingBlockNames(@NonNull List nodes) if (threadNameAction != null) { // If we're on a parallel branch with the same name as the previous (inner) node, that generally // means we're in a Declarative parallel stages situation, so don't add the redundant branch name. - if (names.isEmpty() || !threadNameAction.getThreadName().equals(names.get(names.size()-1))) { + if (names.isEmpty() || !threadNameAction.getThreadName().equals(names.get(names.size() - 1))) { names.add(threadNameAction.getThreadName()); } } else if (labelAction != null) { diff --git a/src/main/java/hudson/tasks/test/AbstractTestResultAction.java b/src/main/java/hudson/tasks/test/AbstractTestResultAction.java index 330a6b51..fd894482 100644 --- a/src/main/java/hudson/tasks/test/AbstractTestResultAction.java +++ b/src/main/java/hudson/tasks/test/AbstractTestResultAction.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Red Hat, Inc., Stephen Connolly, id:cactusman, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -81,7 +81,8 @@ * @author Kohsuke Kawaguchi */ @ExportedBean -public abstract class AbstractTestResultAction implements HealthReportingAction, RunAction2 { +public abstract class AbstractTestResultAction + implements HealthReportingAction, RunAction2 { private static final Logger LOGGER = Logger.getLogger(AbstractTestResultAction.class.getName()); @@ -89,12 +90,13 @@ public abstract class AbstractTestResultAction run; + public transient Run run; + @Deprecated @SuppressFBWarnings(value = "PA_PUBLIC_PRIMITIVE_ATTRIBUTE", justification = "Preserve API compatibility.") - public transient AbstractBuild owner; + public transient AbstractBuild owner; - private Map descriptions = new ConcurrentHashMap<>(); + private Map descriptions = new ConcurrentHashMap<>(); /** @since 1.545 */ protected AbstractTestResultAction() {} @@ -113,26 +115,28 @@ protected AbstractTestResultAction(AbstractBuild owner) { this((Run) owner); } - @Override public void onAttached(Run r) { + @Override + public void onAttached(Run r) { this.run = r; - this.owner = r instanceof AbstractBuild ? (AbstractBuild) r : null; + this.owner = r instanceof AbstractBuild ? (AbstractBuild) r : null; } - @Override public void onLoad(Run r) { + @Override + public void onLoad(Run r) { this.run = r; - this.owner = r instanceof AbstractBuild ? (AbstractBuild) r : null; + this.owner = r instanceof AbstractBuild ? (AbstractBuild) r : null; } /** * Gets the number of failed tests. */ - @Exported(visibility=2) + @Exported(visibility = 2) public abstract int getFailCount(); /** * Gets the number of skipped tests. */ - @Exported(visibility=2) + @Exported(visibility = 2) public int getSkipCount() { // Not all sub-classes will understand the concept of skipped tests. // This default implementation is for them, so that they don't have @@ -145,7 +149,7 @@ public int getSkipCount() { /** * Gets the total number of tests. */ - @Exported(visibility=2) + @Exported(visibility = 2) public abstract int getTotalCount(); /** @@ -153,9 +157,11 @@ public int getSkipCount() { */ public final String getFailureDiffString() { T prev = getPreviousResult(); - if(prev==null) return ""; // no record + if (prev == null) { + return ""; // no record + } - return " / "+Functions.getDiffString(this.getFailCount()-prev.getFailCount()); + return " / " + Functions.getDiffString(this.getFailCount() - prev.getFailCount()); } @Override @@ -163,7 +169,7 @@ public String getDisplayName() { return Messages.AbstractTestResultAction_getDisplayName(); } - @Exported(visibility=2) + @Exported(visibility = 2) @Override public String getUrlName() { return "testReport"; @@ -187,9 +193,9 @@ public HealthReport getBuildHealth() { : (int) (100.0 * Math.max(0.0, Math.min(1.0, 1.0 - (scaleFactor * failCount) / totalCount))); Localizable description, displayName = Messages._AbstractTestResultAction_getDisplayName(); if (totalCount == 0) { - description = Messages._AbstractTestResultAction_zeroTestDescription(displayName); + description = Messages._AbstractTestResultAction_zeroTestDescription(displayName); } else { - description = Messages._AbstractTestResultAction_TestsDescription(displayName, failCount, totalCount); + description = Messages._AbstractTestResultAction_TestsDescription(displayName, failCount, totalCount); } return new HealthReport(score, description); } @@ -230,22 +236,29 @@ public Api getApi() { * Gets the test result of the previous build, if it's recorded, or null. */ public T getPreviousResult() { - return (T)getPreviousResult(getClass(), true); + return (T) getPreviousResult(getClass(), true); } @Restricted(NoExternalUse.class) public U getPreviousResult(Class type, boolean eager) { - Run b = run; + Run b = run; Set loadedBuilds; if (!eager && run.getParent() instanceof LazyBuildMixIn.LazyLoadingJob) { - loadedBuilds = ((LazyBuildMixIn.LazyLoadingJob) run.getParent()).getLazyBuildMixIn()._getRuns().getLoadedBuilds().keySet(); + loadedBuilds = ((LazyBuildMixIn.LazyLoadingJob) run.getParent()) + .getLazyBuildMixIn() + ._getRuns() + .getLoadedBuilds() + .keySet(); } else { loadedBuilds = null; } - while(true) { - b = loadedBuilds == null || loadedBuilds.contains(b.number - /* assuming there are no gaps */1) ? b.getPreviousBuild() : null; - if(b==null) + while (true) { + b = loadedBuilds == null || loadedBuilds.contains(b.number - /* assuming there are no gaps */ 1) + ? b.getPreviousBuild() + : null; + if (b == null) { return null; + } U r = b.getAction(type); if (r != null) { if (r == this) { @@ -258,11 +271,11 @@ public U getPreviousResult(Class type, b } } } - + public TestResult findPreviousCorresponding(TestResult test) { T previousResult = getPreviousResult(); if (previousResult != null) { - TestResult testResult = (TestResult)getResult(); + TestResult testResult = (TestResult) getResult(); return testResult.findCorrespondingResult(test.getId()); } @@ -274,12 +287,12 @@ public TestResult findCorrespondingResult(String id) { if (!(testResult instanceof TestResult)) { return null; } - return ((TestResult)testResult).findCorrespondingResult(id); + return ((TestResult) testResult).findCorrespondingResult(id); } - + /** * A shortcut for summary.jelly - * + * * @return List of failed tests from associated test result. */ public List getFailedTests() { @@ -288,7 +301,7 @@ public List getFailedTests() { /** * A shortcut for scripting - * + * * @return List of passed tests from associated test result. * @since 1.10 */ @@ -299,7 +312,7 @@ public List getPassedTests() { /** * A shortcut for scripting - * + * * @return List of skipped tests from associated test result. * @since 1.10 */ @@ -310,30 +323,32 @@ public List getSkippedTests() { /** * Generates a PNG image for the test result trend. - * + * * @deprecated Replaced by echarts in TODO */ @Deprecated - public void doGraph( StaplerRequest req, StaplerResponse rsp) throws IOException { - if(ChartUtil.awtProblemCause!=null) { + public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException { + if (ChartUtil.awtProblemCause != null) { // not available. send out error message - rsp.sendRedirect2(req.getContextPath()+"/images/headless.png"); + rsp.sendRedirect2(req.getContextPath() + "/images/headless.png"); return; } - if(req.checkIfModified(run.getTimestamp(),rsp)) + if (req.checkIfModified(run.getTimestamp(), rsp)) { return; + } - ChartUtil.generateGraph(req,rsp,createChart(req,buildDataSet(req)),calcDefaultSize()); + ChartUtil.generateGraph(req, rsp, createChart(req, buildDataSet(req)), calcDefaultSize()); } /** * Generates a clickable map HTML for {@link #doGraph(StaplerRequest, StaplerResponse)}. */ - public void doGraphMap( StaplerRequest req, StaplerResponse rsp) throws IOException { - if(req.checkIfModified(run.getTimestamp(),rsp)) + public void doGraphMap(StaplerRequest req, StaplerResponse rsp) throws IOException { + if (req.checkIfModified(run.getTimestamp(), rsp)) { return; - ChartUtil.generateClickableMap(req,rsp,createChart(req,buildDataSet(req)),calcDefaultSize()); + } + ChartUtil.generateClickableMap(req, rsp, createChart(req, buildDataSet(req)), calcDefaultSize()); } /** @@ -351,56 +366,62 @@ public String getTestResultPath(TestResult it) { */ private Area calcDefaultSize() { Area res = Functions.getScreenResolution(); - if(res!=null && res.width<=800) - return new Area(250,100); - else - return new Area(500,200); + if (res != null && res.width <= 800) { + return new Area(250, 100); + } else { + return new Area(500, 200); + } } - + private CategoryDataset buildDataSet(StaplerRequest req) { boolean failureOnly = Boolean.parseBoolean(req.getParameter("failureOnly")); // TODO stop using ChartUtil.NumberOnlyBuildLabel as it forces loading of a Run; create a plainer Comparable - DataSetBuilder dsb = new DataSetBuilder<>(); + DataSetBuilder dsb = new DataSetBuilder<>(); int cap = Integer.getInteger(AbstractTestResultAction.class.getName() + ".test.trend.max", Integer.MAX_VALUE); int count = 0; - for (AbstractTestResultAction a = this; a != null; a = a.getPreviousResult(AbstractTestResultAction.class, false)) { + for (AbstractTestResultAction a = this; + a != null; + a = a.getPreviousResult(AbstractTestResultAction.class, false)) { if (++count > cap) { LOGGER.log(Level.FINE, "capping test trend for {0} at {1}", new Object[] {run, cap}); break; } - dsb.add( a.getFailCount(), "failed", new ChartUtil.NumberOnlyBuildLabel(a.run)); - if(!failureOnly) { - dsb.add( a.getSkipCount(), "skipped", new ChartUtil.NumberOnlyBuildLabel(a.run)); - dsb.add( a.getTotalCount()-a.getFailCount()-a.getSkipCount(),"total", new ChartUtil.NumberOnlyBuildLabel(a.run)); + dsb.add(a.getFailCount(), "failed", new ChartUtil.NumberOnlyBuildLabel(a.run)); + if (!failureOnly) { + dsb.add(a.getSkipCount(), "skipped", new ChartUtil.NumberOnlyBuildLabel(a.run)); + dsb.add( + a.getTotalCount() - a.getFailCount() - a.getSkipCount(), + "total", + new ChartUtil.NumberOnlyBuildLabel(a.run)); } } LOGGER.log(Level.FINER, "total test trend count for {0}: {1}", new Object[] {run, count}); return dsb.build(); } - private JFreeChart createChart(StaplerRequest req,CategoryDataset dataset) { + private JFreeChart createChart(StaplerRequest req, CategoryDataset dataset) { final String relPath = getRelPath(req); final JFreeChart chart = ChartFactory.createStackedAreaChart( - null, // chart title - null, // unused - "count", // range axis label - dataset, // data - PlotOrientation.VERTICAL, // orientation - false, // include legend - true, // tooltips - false // urls - ); + null, // chart title + null, // unused + "count", // range axis label + dataset, // data + PlotOrientation.VERTICAL, // orientation + false, // include legend + true, // tooltips + false // urls + ); // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART... // set the background color for the chart... -// final StandardLegend legend = (StandardLegend) chart.getLegend(); -// legend.setAnchor(StandardLegend.SOUTH); + // final StandardLegend legend = (StandardLegend) chart.getLegend(); + // legend.setAnchor(StandardLegend.SOUTH); chart.setBackgroundPaint(Color.white); @@ -410,8 +431,8 @@ private JFreeChart createChart(StaplerRequest req,CategoryDataset dataset) { plot.setBackgroundPaint(Color.WHITE); plot.setOutlinePaint(null); plot.setForegroundAlpha(0.8f); -// plot.setDomainGridlinesVisible(true); -// plot.setDomainGridlinePaint(Color.white); + // plot.setDomainGridlinesVisible(true); + // plot.setDomainGridlinePaint(Color.white); plot.setRangeGridlinesVisible(true); plot.setRangeGridlinePaint(Color.black); @@ -429,7 +450,7 @@ private JFreeChart createChart(StaplerRequest req,CategoryDataset dataset) { @Override public String generateURL(CategoryDataset dataset, int row, int column) { ChartUtil.NumberOnlyBuildLabel label = (ChartUtil.NumberOnlyBuildLabel) dataset.getColumnKey(column); - return relPath+label.getRun().getNumber()+"/testReport/"; + return relPath + label.getRun().getNumber() + "/testReport/"; } @Override @@ -438,28 +459,33 @@ public String generateToolTip(CategoryDataset dataset, int row, int column) { AbstractTestResultAction a = label.getRun().getAction(AbstractTestResultAction.class); switch (row) { case 0: - return String.valueOf(Messages.AbstractTestResultAction_fail(label.getRun().getDisplayName(), a.getFailCount())); + return String.valueOf(Messages.AbstractTestResultAction_fail( + label.getRun().getDisplayName(), a.getFailCount())); case 1: - return String.valueOf(Messages.AbstractTestResultAction_skip(label.getRun().getDisplayName(), a.getSkipCount())); + return String.valueOf(Messages.AbstractTestResultAction_skip( + label.getRun().getDisplayName(), a.getSkipCount())); default: - return String.valueOf(Messages.AbstractTestResultAction_test(label.getRun().getDisplayName(), a.getTotalCount())); + return String.valueOf(Messages.AbstractTestResultAction_test( + label.getRun().getDisplayName(), a.getTotalCount())); } } }; plot.setRenderer(ar); - ar.setSeriesPaint(0,ColorPalette.RED); // Failures. - ar.setSeriesPaint(1,ColorPalette.YELLOW); // Skips. - ar.setSeriesPaint(2,ColorPalette.BLUE); // Total. + ar.setSeriesPaint(0, ColorPalette.RED); // Failures. + ar.setSeriesPaint(1, ColorPalette.YELLOW); // Skips. + ar.setSeriesPaint(2, ColorPalette.BLUE); // Total. // crop extra space around the graph - plot.setInsets(new RectangleInsets(0,0,0,5.0)); + plot.setInsets(new RectangleInsets(0, 0, 0, 5.0)); return chart; } private String getRelPath(StaplerRequest req) { String relPath = req.getParameter("rel"); - if(relPath==null) return ""; + if (relPath == null) { + return ""; + } return relPath; } @@ -471,67 +497,80 @@ private String getRelPath(StaplerRequest req) { *

* The default implementation stores information in the 'this' object. * - * @see TestObject#getDescription() + * @see TestObject#getDescription() */ protected String getDescription(TestObject object) { - return descriptions.get(object.getId()); + return descriptions.get(object.getId()); } protected void setDescription(TestObject object, String description) { - descriptions.put(object.getId(), description); + descriptions.put(object.getId(), description); } public Object readResolve() { - if (descriptions == null) { - descriptions = new ConcurrentHashMap<>(); - } - - return this; + if (descriptions == null) { + descriptions = new ConcurrentHashMap<>(); + } + + return this; } - @Extension public static final class Summarizer extends Run.StatusSummarizer { - @Override public Run.Summary summarize(Run run, ResultTrend trend) { + @Extension + public static final class Summarizer extends Run.StatusSummarizer { + @Override + public Run.Summary summarize(Run run, ResultTrend trend) { AbstractTestResultAction trN = run.getAction(AbstractTestResultAction.class); if (trN == null) { return null; } Boolean worseOverride; switch (trend) { - case NOW_UNSTABLE: - worseOverride = false; - break; - case UNSTABLE: - worseOverride = true; - break; - case STILL_UNSTABLE: - worseOverride = null; - break; - default: - return null; + case NOW_UNSTABLE: + worseOverride = false; + break; + case UNSTABLE: + worseOverride = true; + break; + case STILL_UNSTABLE: + worseOverride = null; + break; + default: + return null; } Run prev = run.getPreviousBuild(); AbstractTestResultAction trP = prev == null ? null : prev.getAction(AbstractTestResultAction.class); if (trP == null) { if (trN.getFailCount() > 0) { - return new Run.Summary(worseOverride != null ? worseOverride : true, Messages.Run_Summary_TestFailures(trN.getFailCount())); + return new Run.Summary( + worseOverride != null ? worseOverride : true, + Messages.Run_Summary_TestFailures(trN.getFailCount())); } } else { if (trN.getFailCount() != 0) { if (trP.getFailCount() == 0) { - return new Run.Summary(worseOverride != null ? worseOverride : true, Messages.Run_Summary_TestsStartedToFail(trN.getFailCount())); + return new Run.Summary( + worseOverride != null ? worseOverride : true, + Messages.Run_Summary_TestsStartedToFail(trN.getFailCount())); } if (trP.getFailCount() < trN.getFailCount()) { - return new Run.Summary(worseOverride != null ? worseOverride : true, Messages.Run_Summary_MoreTestsFailing(trN.getFailCount() - trP.getFailCount(), trN.getFailCount())); + return new Run.Summary( + worseOverride != null ? worseOverride : true, + Messages.Run_Summary_MoreTestsFailing( + trN.getFailCount() - trP.getFailCount(), trN.getFailCount())); } if (trP.getFailCount() > trN.getFailCount()) { - return new Run.Summary(worseOverride != null ? worseOverride : false, Messages.Run_Summary_LessTestsFailing(trP.getFailCount() - trN.getFailCount(), trN.getFailCount())); + return new Run.Summary( + worseOverride != null ? worseOverride : false, + Messages.Run_Summary_LessTestsFailing( + trP.getFailCount() - trN.getFailCount(), trN.getFailCount())); } - return new Run.Summary(worseOverride != null ? worseOverride : false, Messages.Run_Summary_TestsStillFailing(trN.getFailCount())); + return new Run.Summary( + worseOverride != null ? worseOverride : false, + Messages.Run_Summary_TestsStillFailing(trN.getFailCount())); } } return null; } } - } diff --git a/src/main/java/hudson/tasks/test/AggregatedTestResultAction.java b/src/main/java/hudson/tasks/test/AggregatedTestResultAction.java index c0b35ce5..c2c6026e 100644 --- a/src/main/java/hudson/tasks/test/AggregatedTestResultAction.java +++ b/src/main/java/hudson/tasks/test/AggregatedTestResultAction.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Red Hat, Inc., Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,7 +43,7 @@ */ @ExportedBean public abstract class AggregatedTestResultAction extends AbstractTestResultAction { - private int failCount,skipCount,totalCount; + private int failCount, skipCount, totalCount; public static final class Child { /** @@ -53,6 +53,7 @@ public static final class Child { * {@link AggregatedTestResultAction#resolveChild(Child)} and */ public final String name; + public final int build; public Child(String name, int build) { @@ -77,15 +78,16 @@ public AggregatedTestResultAction() {} protected void update(List children) { failCount = skipCount = totalCount = 0; this.children.clear(); - for (AbstractTestResultAction tr : children) + for (AbstractTestResultAction tr : children) { add(tr); + } } protected void add(AbstractTestResultAction child) { failCount += child.getFailCount(); skipCount += child.getSkipCount(); totalCount += child.getTotalCount(); - this.children.add(new Child(getChildName(child),child.run.number)); + this.children.add(new Child(getChildName(child), child.run.number)); } @Override @@ -102,7 +104,7 @@ public int getSkipCount() { public int getTotalCount() { return totalCount; } - + @Override public List getResult() { // I think this is a reasonable default. @@ -123,15 +125,16 @@ public List getFailedTests() { /** * Data-binding bean for the remote API. */ - @ExportedBean(defaultVisibility=2) + @ExportedBean(defaultVisibility = 2) public static final class ChildReport { @Deprecated - public final AbstractBuild child; + public final AbstractBuild child; /** * @since 1.2-beta-1 */ - @Exported(name="child") - public final Run run; + @Exported(name = "child") + public final Run run; + @Exported public final Object result; @@ -143,24 +146,22 @@ public ChildReport(AbstractBuild child, AbstractTestResultAction result) { /** * @since 1.2-beta-1 */ - public ChildReport(Run run, AbstractTestResultAction result) { + public ChildReport(Run run, AbstractTestResultAction result) { this.child = run instanceof AbstractBuild ? (AbstractBuild) run : null; this.run = run; - this.result = result!=null ? result.getResult() : null; + this.result = result != null ? result.getResult() : null; } } /** * Mainly for the remote API. Expose results from children. */ - @Exported(inline=true) + @Exported(inline = true) public List getChildReports() { return new AbstractList() { @Override public ChildReport get(int index) { - return new ChildReport( - resolveRun(children.get(index)), - getChildReport(children.get(index))); + return new ChildReport(resolveRun(children.get(index)), getChildReport(children.get(index))); } @Override @@ -175,14 +176,14 @@ public int size() { /** * @since 1.2-beta-1 */ - public Run resolveRun(Child child) { + public Run resolveRun(Child child) { return resolveChild(child); } @Deprecated - public AbstractBuild resolveChild(Child child) { + public AbstractBuild resolveChild(Child child) { if (Util.isOverridden(AggregatedTestResultAction.class, getClass(), "resolveRun", Child.class)) { - Run r = resolveRun(child); + Run r = resolveRun(child); return r instanceof AbstractBuild ? (AbstractBuild) r : null; } else { throw new AbstractMethodError("you must override resolveRun"); @@ -194,8 +195,10 @@ public AbstractBuild resolveChild(Child child) { * {@link AbstractTestResultAction} object for the given child. */ protected AbstractTestResultAction getChildReport(Child child) { - Run b = resolveRun(child); - if(b==null) return null; + Run b = resolveRun(child); + if (b == null) { + return null; + } return b.getAction(AbstractTestResultAction.class); } @@ -207,6 +210,7 @@ protected AbstractTestResultAction getChildReport(Child child) { * @deprecated * so that IDE warns you if you accidentally try to call it. */ + @Deprecated @Override protected final String getDescription(TestObject object) { throw new AssertionError(); @@ -218,6 +222,7 @@ protected final String getDescription(TestObject object) { * @deprecated * so that IDE warns you if you accidentally try to call it. */ + @Deprecated @Override protected final void setDescription(TestObject object, String description) { throw new AssertionError(); diff --git a/src/main/java/hudson/tasks/test/AggregatedTestResultPublisher.java b/src/main/java/hudson/tasks/test/AggregatedTestResultPublisher.java index 109c0298..cada0e75 100644 --- a/src/main/java/hudson/tasks/test/AggregatedTestResultPublisher.java +++ b/src/main/java/hudson/tasks/test/AggregatedTestResultPublisher.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Michael B. Donohue, Yahoo!, Inc., Andrew Bayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -83,14 +83,15 @@ public class AggregatedTestResultPublisher extends Recorder { public AggregatedTestResultPublisher(String jobs) { this(jobs, false); } - + public AggregatedTestResultPublisher(String jobs, boolean includeFailedBuilds) { this.jobs = Util.fixEmptyAndTrim(jobs); this.includeFailedBuilds = includeFailedBuilds; } @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { // add a TestResult just so that it can show up later. build.addAction(new TestResultAction(jobs, includeFailedBuilds, build)); return true; @@ -101,7 +102,8 @@ public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } - @Override public Collection getProjectActions(AbstractProject project) { + @Override + public Collection getProjectActions(AbstractProject project) { return Collections.singleton(new TestResultProjectAction(project)); } @@ -122,7 +124,7 @@ public static final class TestResultAction extends AbstractTestResultAction { * Should failed builds be included? */ private final boolean includeFailedBuilds; - + /** * The last time the fields of this object is computed from the rest. */ @@ -139,18 +141,21 @@ public static final class TestResultAction extends AbstractTestResultAction { * Projects that haven't run yet. */ private transient List didntRun; + private transient List noFingerprints; @SuppressWarnings("deprecation") // calls getProject in constructor, so needs owner immediately - public TestResultAction(String jobs, boolean includeFailedBuilds, AbstractBuild owner) { + public TestResultAction(String jobs, boolean includeFailedBuilds, AbstractBuild owner) { super(owner); this.includeFailedBuilds = includeFailedBuilds; - - if(jobs==null) { + + if (jobs == null) { // resolve null as the transitive downstream jobs StringBuilder buf = new StringBuilder(); for (AbstractProject p : getProject().getTransitiveDownstreamProjects()) { - if(buf.length()>0) buf.append(','); + if (buf.length() > 0) { + buf.append(','); + } buf.append(p.getFullName()); } jobs = buf.toString(); @@ -164,7 +169,7 @@ public TestResultAction(String jobs, boolean includeFailedBuilds, AbstractBuild< public Collection getJobs() { List r = new ArrayList<>(); if (jobs != null) { - for (String job : Util.tokenize(jobs,",")) { + for (String job : Util.tokenize(jobs, ",")) { try { AbstractProject j = Jenkins.get().getItemByFullName(job.trim(), AbstractProject.class); if (j != null) { @@ -185,8 +190,8 @@ public Collection getJobs() { public boolean getIncludeFailedBuilds() { return includeFailedBuilds; } - - private AbstractProject getProject() { + + private AbstractProject getProject() { return owner.getProject(); } @@ -216,6 +221,7 @@ public Object getResult() { * @deprecated * so that IDE warns you if you accidentally try to call it. */ + @Deprecated @Override protected String getDescription(TestObject object) { throw new AssertionError(); @@ -227,6 +233,7 @@ protected String getDescription(TestObject object) { * @deprecated * so that IDE warns you if you accidentally try to call it. */ + @Deprecated @Override protected void setDescription(TestObject object, String description) { throw new AssertionError(); @@ -248,8 +255,8 @@ public List getDidntRun() { return Collections.unmodifiableList(didntRun); } - /** - * Gets the downstream projects that have available test results, but + /** + * Gets the downstream projects that have available test results, but * do not appear to have fingerprinting enabled. */ public List getNoFingerprints() { @@ -259,11 +266,15 @@ public List getNoFingerprints() { /** * Makes sure that the data fields are up to date. */ - @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "False positive. Short-circuited") + @SuppressFBWarnings( + value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", + justification = "False positive. Short-circuited") private synchronized void upToDateCheck() { // up to date check - if(lastUpdated>lastChanged) return; - lastUpdated = lastChanged+1; + if (lastUpdated > lastChanged) { + return; + } + lastUpdated = lastChanged + 1; int failCount = 0; int totalCount = 0; @@ -272,7 +283,7 @@ private synchronized void upToDateCheck() { List noFingerprints = new ArrayList<>(); for (AbstractProject job : getJobs()) { Fingerprint.RangeSet rs = owner.getDownstreamRelationship(job); - if(rs.isEmpty()) { + if (rs.isEmpty()) { // is this job expected to produce a test result? Run b; if (includeFailedBuilds) { @@ -280,8 +291,8 @@ private synchronized void upToDateCheck() { } else { b = job.getLastSuccessfulBuild(); } - if(b!=null && b.getAction(AbstractTestResultAction.class)!=null) { - if(b.getAction(Fingerprinter.FingerprintAction.class)!=null) { + if (b != null && b.getAction(AbstractTestResultAction.class) != null) { + if (b.getAction(Fingerprinter.FingerprintAction.class) != null) { didntRun.add(job); } else { noFingerprints.add(job); @@ -290,18 +301,23 @@ private synchronized void upToDateCheck() { } else { for (int n : rs.listNumbersReverse()) { Run b = job.getBuildByNumber(n); - if(b==null) continue; + if (b == null) { + continue; + } Result targetResult; if (includeFailedBuilds) { targetResult = Result.FAILURE; } else { targetResult = Result.UNSTABLE; } - - if(b.isBuilding() || b.getResult() == null || b.getResult().isWorseThan(targetResult)) - continue; // don't count them - for( AbstractTestResultAction ta : b.getActions(AbstractTestResultAction.class)) { + if (b.isBuilding() + || b.getResult() == null + || b.getResult().isWorseThan(targetResult)) { + continue; // don't count them + } + + for (AbstractTestResultAction ta : b.getActions(AbstractTestResultAction.class)) { failCount += ta.getFailCount(); totalCount += ta.getTotalCount(); individuals.add(ta); @@ -319,7 +335,7 @@ private synchronized void upToDateCheck() { } public boolean getHasFingerprintAction() { - return this.owner.getAction(Fingerprinter.FingerprintAction.class)!=null; + return this.owner.getAction(Fingerprinter.FingerprintAction.class) != null; } @Override @@ -346,7 +362,7 @@ public static final class DescriptorImpl extends BuildStepDescriptor @Override public boolean isApplicable(Class jobType) { - return true; // for all types + return true; // for all types } @Override @@ -356,16 +372,19 @@ public String getDisplayName() { public FormValidation doCheck(@AncestorInPath AbstractProject project, @QueryParameter String value) { // Require CONFIGURE permission on this project - if(!project.hasPermission(Item.CONFIGURE)) return FormValidation.ok(); + if (!project.hasPermission(Item.CONFIGURE)) { + return FormValidation.ok(); + } for (String name : Util.tokenize(Util.fixNull(value), ",")) { name = name.trim(); - if (Jenkins.get().getItem(name,project) == null) { - final AbstractProject nearest = AbstractProject.findNearest(name); - return FormValidation.error(Messages.BuildTrigger_NoSuchProject(name, nearest != null ? nearest.getName() : null)); + if (Jenkins.get().getItem(name, project) == null) { + final AbstractProject nearest = AbstractProject.findNearest(name); + return FormValidation.error( + Messages.BuildTrigger_NoSuchProject(name, nearest != null ? nearest.getName() : null)); } } - + return FormValidation.ok(); } @@ -378,24 +397,28 @@ public AggregatedTestResultPublisher newInstance(StaplerRequest req, JSONObject throw new AssertionError("Null parameters to Descriptor#newInstance"); } JSONObject s = formData.getJSONObject("specify"); - if(s.isNullObject()) - return new AggregatedTestResultPublisher(null, req != null && req.getParameter("includeFailedBuilds") != null); - else - return new AggregatedTestResultPublisher(s.getString("jobs"), req != null && req.getParameter("includeFailedBuilds") != null); + if (s.isNullObject()) { + return new AggregatedTestResultPublisher( + null, req != null && req.getParameter("includeFailedBuilds") != null); + } else { + return new AggregatedTestResultPublisher( + s.getString("jobs"), req != null && req.getParameter("includeFailedBuilds") != null); + } } - public AutoCompletionCandidates doAutoCompleteJobs(@QueryParameter String value, @AncestorInPath Item self, @AncestorInPath ItemGroup container) { + public AutoCompletionCandidates doAutoCompleteJobs( + @QueryParameter String value, @AncestorInPath Item self, @AncestorInPath ItemGroup container) { // Item.READ checked inside - return AutoCompletionCandidates.ofJobNames(Job.class,value,self,container); + return AutoCompletionCandidates.ofJobNames(Job.class, value, self, container); } } @Restricted(NoExternalUse.class) public static final class TestResultProjectAction extends InvisibleAction { public final AbstractProject project; - private TestResultProjectAction(AbstractProject project) { + + private TestResultProjectAction(AbstractProject project) { this.project = project; } } - } diff --git a/src/main/java/hudson/tasks/test/DefaultTestResultParserImpl.java b/src/main/java/hudson/tasks/test/DefaultTestResultParserImpl.java index 9755abde..684ad6df 100644 --- a/src/main/java/hudson/tasks/test/DefaultTestResultParserImpl.java +++ b/src/main/java/hudson/tasks/test/DefaultTestResultParserImpl.java @@ -71,12 +71,20 @@ public abstract class DefaultTestResultParserImpl extends TestResultParser imple * If you encounter an error that you handled gracefully, throw this exception and Hudson * will not show a stack trace. */ - protected abstract TestResult parse(List reportFiles, Launcher launcher, TaskListener listener) throws InterruptedException, IOException; + protected abstract TestResult parse(List reportFiles, Launcher launcher, TaskListener listener) + throws InterruptedException, IOException; @Override - public TestResult parseResult(final String testResultLocations, final Run build, FilePath workspace, final Launcher launcher, final TaskListener listener) throws InterruptedException, IOException { + public TestResult parseResult( + final String testResultLocations, + final Run build, + FilePath workspace, + final Launcher launcher, + final TaskListener listener) + throws InterruptedException, IOException { return workspace.act(new MasterToSlaveFileCallable() { - final boolean ignoreTimestampCheck = IGNORE_TIMESTAMP_CHECK; // so that the property can be set on the controller + final boolean ignoreTimestampCheck = + IGNORE_TIMESTAMP_CHECK; // so that the property can be set on the controller final long buildTime = build.getTimestamp().getTimeInMillis(); final long nowMaster = System.currentTimeMillis(); @@ -88,14 +96,18 @@ public TestResult invoke(File dir, VirtualChannel channel) throws IOException, I long localBuildTime = buildTime + (nowSlave - nowMaster); FilePath[] paths = new FilePath(dir).list(testResultLocations); - if (paths.length==0) - throw new AbortException("No test reports that matches "+testResultLocations+" found. Configuration error?"); + if (paths.length == 0) { + throw new AbortException( + "No test reports that matches " + testResultLocations + " found. Configuration error?"); + } // since dir is local, paths all point to the local files List files = new ArrayList<>(paths.length); for (FilePath path : paths) { File report = new File(path.getRemote()); - if (ignoreTimestampCheck || localBuildTime - hudson.tasks.junit.TestResult.FILE_TIME_PRECISION_MARGIN < report.lastModified()) { + if (ignoreTimestampCheck + || localBuildTime - hudson.tasks.junit.TestResult.FILE_TIME_PRECISION_MARGIN + < report.lastModified()) { // this file is created during this build files.add(report); } @@ -103,19 +115,19 @@ public TestResult invoke(File dir, VirtualChannel channel) throws IOException, I if (files.isEmpty()) { // none of the files were new - throw new AbortException( - String.format( - "Test reports were found but none of them are new. Did tests run? %n"+ - "For example, %s is %s old%n", paths[0].getRemote(), - Util.getTimeSpanString(localBuildTime-paths[0].lastModified()))); + throw new AbortException(String.format( + "Test reports were found but none of them are new. Did tests run? %n" + + "For example, %s is %s old%n", + paths[0].getRemote(), Util.getTimeSpanString(localBuildTime - paths[0].lastModified()))); } - return parse(files,launcher,listener); + return parse(files, launcher, listener); } }); } private static final long serialVersionUID = 1L; - public static final boolean IGNORE_TIMESTAMP_CHECK = Boolean.getBoolean(TestResultParser.class.getName()+".ignoreTimestampCheck"); + public static final boolean IGNORE_TIMESTAMP_CHECK = + Boolean.getBoolean(TestResultParser.class.getName() + ".ignoreTimestampCheck"); } diff --git a/src/main/java/hudson/tasks/test/MetaTabulatedResult.java b/src/main/java/hudson/tasks/test/MetaTabulatedResult.java index 3fd68112..bb260b46 100644 --- a/src/main/java/hudson/tasks/test/MetaTabulatedResult.java +++ b/src/main/java/hudson/tasks/test/MetaTabulatedResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,12 +23,11 @@ */ package hudson.tasks.test; - import java.util.Collection; /** * The purpose of this class is to provide a good place for the - * jelly to bind to. + * jelly to bind to. * {@link TabulatedResult} whose immediate children * are other {@link TabulatedResult}s. * @@ -41,5 +40,4 @@ public abstract class MetaTabulatedResult extends TabulatedResult { */ @Override public abstract Collection getFailedTests(); - } diff --git a/src/main/java/hudson/tasks/test/PipelineBlockWithTests.java b/src/main/java/hudson/tasks/test/PipelineBlockWithTests.java index 57d56254..15e04eb0 100644 --- a/src/main/java/hudson/tasks/test/PipelineBlockWithTests.java +++ b/src/main/java/hudson/tasks/test/PipelineBlockWithTests.java @@ -9,7 +9,7 @@ public class PipelineBlockWithTests implements Serializable { private final String blockId; - private final Map childBlocks = new TreeMap<>(); + private final Map childBlocks = new TreeMap<>(); private final Set leafNodes = new TreeSet<>(); public PipelineBlockWithTests(@NonNull String blockId) { @@ -22,7 +22,7 @@ public String getBlockId() { } @NonNull - public Map getChildBlocks() { + public Map getChildBlocks() { return childBlocks; } @@ -35,7 +35,7 @@ public void addChildBlock(@NonNull PipelineBlockWithTests child) { childBlocks.put(child.getBlockId(), child); } - public void addLeafNode(@NonNull String leafNode) { + public void addLeafNode(@NonNull String leafNode) { leafNodes.add(leafNode); } @@ -67,9 +67,9 @@ public boolean equals(Object o) { } PipelineBlockWithTests that = (PipelineBlockWithTests) o; - return that.getBlockId().equals(getBlockId()) && - that.getChildBlocks().equals(getChildBlocks()) && - that.getLeafNodes().equals(getLeafNodes()); + return that.getBlockId().equals(getBlockId()) + && that.getChildBlocks().equals(getChildBlocks()) + && that.getLeafNodes().equals(getLeafNodes()); } @Override diff --git a/src/main/java/hudson/tasks/test/SimpleCaseResult.java b/src/main/java/hudson/tasks/test/SimpleCaseResult.java index 2474f0f2..8ba224ed 100644 --- a/src/main/java/hudson/tasks/test/SimpleCaseResult.java +++ b/src/main/java/hudson/tasks/test/SimpleCaseResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -42,16 +42,16 @@ public class SimpleCaseResult extends TestResult { private static final Logger LOGGER = Logger.getLogger(SimpleCaseResult.class.getName()); public SimpleCaseResult(float duration) { - listOnlyContainingThisObject.add(this); + listOnlyContainingThisObject.add(this); } - + public SimpleCaseResult() { this(1.0f); } /** * Sets the parent action, which means the action that binds - * this particular case result to a build. Should not be null. + * this particular case result to a build. Should not be null. * @param parentAction */ @Override @@ -68,7 +68,7 @@ public AbstractTestResultAction getParentAction() { public TestObject getParent() { return null; } - + @Override public TestResult findCorrespondingResult(String id) { if (id.equals(getId())) { @@ -77,7 +77,7 @@ public TestResult findCorrespondingResult(String id) { return null; } - + /** * Gets the "children" of this test result that failed * @@ -130,11 +130,11 @@ public boolean isSkipped() { * Returns true iff this test failed. */ public boolean isFailed() { - return false; + return false; } /** - * Time took to run this test. In seconds. + * Time took to run this test. In seconds. */ @Override public float getDuration() { @@ -178,7 +178,7 @@ public int getSkipCount() { */ @Override public String getTitle() { - return "Simple Case Result"; // + return "Simple Case Result"; // } @Override @@ -187,10 +187,10 @@ public String getDisplayName() { } @Override - public Run getRun() { + public Run getRun() { if (parentAction == null) { LOGGER.warning("in Trivial Test Result, parentAction is null, but getRun() called"); - return null; + return null; } return parentAction.run; } @@ -200,13 +200,8 @@ public List getTestActions() { return SimpleCaseResult.EMPTY_ACTION_LIST; } - /** * An empty list of actions, useful for tests */ public static final List EMPTY_ACTION_LIST = Collections.unmodifiableList(new ArrayList<>()); - - - - } diff --git a/src/main/java/hudson/tasks/test/TabulatedResult.java b/src/main/java/hudson/tasks/test/TabulatedResult.java index 778234d8..32941638 100644 --- a/src/main/java/hudson/tasks/test/TabulatedResult.java +++ b/src/main/java/hudson/tasks/test/TabulatedResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,7 +43,7 @@ public abstract class TabulatedResult extends TestResult { /** * TODO: javadoc */ - protected transient Map testsByBlock; + protected transient Map testsByBlock; /** * Gets the child test result objects. @@ -78,8 +78,8 @@ public PipelineBlockWithTests getPipelineBlockWithTests(@NonNull String blockId) return null; } - protected final void populateBlocks(@NonNull List innermostFirst, @NonNull String nodeId, - @CheckForNull PipelineBlockWithTests nested) { + protected final void populateBlocks( + @NonNull List innermostFirst, @NonNull String nodeId, @CheckForNull PipelineBlockWithTests nested) { if (innermostFirst.isEmpty()) { if (nested != null) { addOrMergeBlock(nested); @@ -114,7 +114,8 @@ private void addOrMergeBlock(@NonNull PipelineBlockWithTests b) { * Default implementation just returns the original. */ @NonNull - public TabulatedResult blockToTestResult(@NonNull PipelineBlockWithTests block, @NonNull TabulatedResult fullResult) { + public TabulatedResult blockToTestResult( + @NonNull PipelineBlockWithTests block, @NonNull TabulatedResult fullResult) { return fullResult; } diff --git a/src/main/java/hudson/tasks/test/TestObject.java b/src/main/java/hudson/tasks/test/TestObject.java index 29ab7cab..a2f2ebdb 100644 --- a/src/main/java/hudson/tasks/test/TestObject.java +++ b/src/main/java/hudson/tasks/test/TestObject.java @@ -1,19 +1,19 @@ /* * The MIT License - * + * * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, * Tom Huybrechts, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -62,8 +62,8 @@ * Base class for all test result objects. * For compatibility with code that expects this class to be in hudson.tasks.junit, * we've created a pure-abstract class, hudson.tasks.junit.TestObject. That - * stub class is deprecated; instead, people should use this class. - * + * stub class is deprecated; instead, people should use this class. + * * @author Kohsuke Kawaguchi */ @ExportedBean @@ -71,7 +71,7 @@ public abstract class TestObject extends hudson.tasks.junit.TestObject { private static final Logger LOGGER = Logger.getLogger(TestObject.class.getName()); - private volatile transient String id; + private transient volatile String id; /** * Reverse pointer of {@link TabulatedResult#getChildren()}. @@ -115,6 +115,7 @@ public String getFullDisplayName() { * @deprecated This method returns a JUnit specific class. Use * {@link #getTopLevelTestResult()} instead for a more general interface. */ + @Deprecated @Override public hudson.tasks.junit.TestResult getTestResult() { TestObject parent = getParent(); @@ -126,13 +127,13 @@ public hudson.tasks.junit.TestResult getTestResult() { * Returns the top level test result data. * * @return the top level test result data. - */ + */ public TestResult getTopLevelTestResult() { TestObject parent = getParent(); return parent == null ? null : getParent().getTopLevelTestResult(); } - + /** * Computes the relative path to get to this test object from it. If * it does not appear in the parent chain for this object, a @@ -144,65 +145,64 @@ public TestResult getTopLevelTestResult() { */ public String getRelativePathFrom(TestObject it) { - // if (it is one of my ancestors) { // return a relative path from it // } else { // return a complete path starting with "/" // } - if (it==this) { + if (it == this) { return "."; } StringBuilder buf = new StringBuilder(); TestObject next = this; - TestObject cur = this; + TestObject cur = this; // Walk up my ancestors from leaf to root, looking for "it" // and accumulating a relative url as I go - while (next!=null && it!=next) { + while (next != null && it != next) { cur = next; - buf.insert(0,'/'); - buf.insert(0,cur.getSafeName()); + buf.insert(0, '/'); + buf.insert(0, cur.getSafeName()); next = cur.getParent(); } - if (it==next) { + if (it == next) { return buf.toString(); } else { // Keep adding on to the string we've built so far // Start with the test result action AbstractTestResultAction action = getTestResultAction(); - if (action==null) { + if (action == null) { LOGGER.warning("trying to get relative path, but we can't determine the action that owns this result."); return ""; // this won't take us to the right place, but it also won't 404. } - buf.insert(0,'/'); - buf.insert(0,action.getUrlName()); + buf.insert(0, '/'); + buf.insert(0, action.getUrlName()); // Now the build - Run myBuild = cur.getRun(); - if (myBuild ==null) { + Run myBuild = cur.getRun(); + if (myBuild == null) { LOGGER.warning("trying to get relative path, but we can't determine the build that owns this result."); return ""; // this won't take us to the right place, but it also won't 404. } - buf.insert(0,'/'); - buf.insert(0,myBuild.getUrl()); + buf.insert(0, '/'); + buf.insert(0, myBuild.getUrl()); // If we're inside a stapler request, just delegate to Hudson.Functions to get the relative path! StaplerRequest req = Stapler.getCurrentRequest(); - if (req!=null && myBuild instanceof Item) { + if (req != null && myBuild instanceof Item) { buf.insert(0, '/'); // Ugly but I don't see how else to convince the compiler that myBuild is an Item Item myBuildAsItem = (Item) myBuild; buf.insert(0, Functions.getRelativeLinkTo(myBuildAsItem)); } else { // We're not in a stapler request. Okay, give up. - LOGGER.fine("trying to get relative path, but it is not my ancestor, and we are not in a stapler request. Trying absolute jenkins url..."); + LOGGER.fine( + "trying to get relative path, but it is not my ancestor, and we are not in a stapler request. Trying absolute jenkins url..."); String jenkinsUrl = Jenkins.get().getRootUrl(); if (jenkinsUrl == null || jenkinsUrl.length() == 0) { - LOGGER.warning("Can't find anything like a decent hudson url. Punting, returning empty string."); + LOGGER.warning("Can't find anything like a decent hudson url. Punting, returning empty string."); return ""; - } if (!jenkinsUrl.endsWith("/")) { buf.insert(0, '/'); @@ -211,15 +211,14 @@ public String getRelativePathFrom(TestObject it) { } LOGGER.log(Level.FINE, "Here is our relative path: {0}", buf); - return buf.toString(); + return buf.toString(); } - } /** * Subclasses may override this method if they are * associated with a particular subclass of - * AbstractTestResultAction. + * AbstractTestResultAction. * * @return the test result action that connects this test result to a particular build */ @@ -239,7 +238,7 @@ public AbstractTestResultAction getTestResultAction() { } /** - * Get a list of all TestActions associated with this TestObject. + * Get a list of all TestActions associated with this TestObject. */ @Override @Exported(visibility = 3) @@ -254,7 +253,7 @@ public List getTestActions() { } /** - * Gets a test action of the class passed in. + * Gets a test action of the class passed in. * @param klazz Type of the action to return. * @param an instance of the class passed in */ @@ -287,7 +286,8 @@ public TestResult getResultInBuild(AbstractBuild build) { * * @return null if no such counter part exists. */ - @Override public TestResult getResultInRun(Run run) { + @Override + public TestResult getResultInRun(Run run) { return (TestResult) super.getResultInRun(run); } @@ -345,7 +345,7 @@ public Api getApi() { * Gets the name of this object. */ @Override - public/* abstract */ String getName() { + public /* abstract */ String getName() { return ""; } @@ -364,7 +364,6 @@ public String getFullName() { return sb.toString(); } - /** * Gets the version of {@link #getName()} that's URL-safe. */ @@ -388,7 +387,7 @@ public String getSearchUrl() { protected final String uniquifyName(Collection siblings, String base) { synchronized (UNIQUIFIED_NAMES) { String uniquified = base; - Map taken = UNIQUIFIED_NAMES.get(base); + Map taken = UNIQUIFIED_NAMES.get(base); if (taken == null) { taken = new WeakHashMap<>(); UNIQUIFIED_NAMES.put(base, taken); @@ -403,7 +402,8 @@ protected final String uniquifyName(Collection siblings, S return uniquified; } } - private static final Map> UNIQUIFIED_NAMES = new HashMap<>(); + + private static final Map> UNIQUIFIED_NAMES = new HashMap<>(); /** * Replaces URL-unsafe characters. @@ -418,8 +418,16 @@ public static String safe(String s) { return "(empty)"; } else { // this still seems to be a bit faster than a single replace with regexp - return s.replace('/', '_').replace('\\', '_').replace(':', '_').replace('?', '_').replace('#', '_').replace('%', '_').replace('<', '_').replace('>', '_'); - // Note: we probably should some helpers like Commons URIEscapeUtils here to escape all invalid URL chars, but then we + return s.replace('/', '_') + .replace('\\', '_') + .replace(':', '_') + .replace('?', '_') + .replace('#', '_') + .replace('%', '_') + .replace('<', '_') + .replace('>', '_'); + // Note: we probably should some helpers like Commons URIEscapeUtils here to escape all invalid URL chars, + // but then we // still would have to escape /, ? and so on } } @@ -455,8 +463,7 @@ public History getHistory() { return new History(this); } - public Object getDynamic(String token, StaplerRequest req, - StaplerResponse rsp) { + public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) { for (Action a : getTestActions()) { if (a == null) { continue; // be defensive @@ -473,9 +480,8 @@ public Object getDynamic(String token, StaplerRequest req, } @RequirePOST - public synchronized HttpResponse doSubmitDescription( - @QueryParameter String description) throws IOException, - ServletException { + public synchronized HttpResponse doSubmitDescription(@QueryParameter String description) + throws IOException, ServletException { Run run = getRun(); if (run == null) { LOGGER.severe("getRun() is null, can't save description."); @@ -487,5 +493,6 @@ public synchronized HttpResponse doSubmitDescription( return new HttpRedirect("."); } + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/hudson/tasks/test/TestObjectIterable.java b/src/main/java/hudson/tasks/test/TestObjectIterable.java index 73fe4bd5..c9416695 100644 --- a/src/main/java/hudson/tasks/test/TestObjectIterable.java +++ b/src/main/java/hudson/tasks/test/TestObjectIterable.java @@ -13,7 +13,7 @@ public class TestObjectIterable implements Iterable> { private final TestObject latestAction; private final List items; - + /** * Creates a new iterator that selects action of the given type {@code actionType}. * @@ -24,32 +24,30 @@ public TestObjectIterable(final TestObject baseline) { this.latestAction = baseline; this.items = null; } - + public TestObjectIterable(final TestObject baseline, List results) { this.latestAction = baseline; - this.items = results - .stream() - .map(r -> (TestObject)baseline.getResultInRun(r.getRun())) - .filter(r -> r != null) - .collect(Collectors.toList()); + this.items = results.stream() + .map(r -> (TestObject) baseline.getResultInRun(r.getRun())) + .filter(r -> r != null) + .collect(Collectors.toList()); } - + @NonNull @Override public Iterator> iterator() { if (items == null) { return new TestResultActionIterator(latestAction); } - return items - .stream() - .map(t -> { - Run run = t.getRun(); - int buildTimeInSeconds = (int) (run.getTimeInMillis() / 1000); - Build build = new Build(run.getNumber(), run.getDisplayName(), buildTimeInSeconds); - return new BuildResult<>(build, t); - }) - .collect(Collectors.toList()) - .iterator(); + return items.stream() + .map(t -> { + Run run = t.getRun(); + int buildTimeInSeconds = (int) (run.getTimeInMillis() / 1000); + Build build = new Build(run.getNumber(), run.getDisplayName(), buildTimeInSeconds); + return new BuildResult<>(build, t); + }) + .collect(Collectors.toList()) + .iterator(); } private static class TestResultActionIterator implements Iterator> { @@ -71,11 +69,11 @@ public boolean hasNext() { if (initialValue != null) { return true; } - + if (cursor == null) { return false; } - + TestResult previousBuild = cursor.getPreviousResult(); return previousBuild != null; } diff --git a/src/main/java/hudson/tasks/test/TestObjectTrendSeriesBuilder.java b/src/main/java/hudson/tasks/test/TestObjectTrendSeriesBuilder.java index 39ae3f61..f005f31b 100644 --- a/src/main/java/hudson/tasks/test/TestObjectTrendSeriesBuilder.java +++ b/src/main/java/hudson/tasks/test/TestObjectTrendSeriesBuilder.java @@ -12,7 +12,7 @@ public class TestObjectTrendSeriesBuilder extends SeriesBuilder { @Override protected Map computeSeries(TestObject testObject) { Map series = new HashMap<>(); - + int totalCount = testObject.getTotalCount(); int failCount = testObject.getFailCount(); int skipCount = testObject.getSkipCount(); diff --git a/src/main/java/hudson/tasks/test/TestResult.java b/src/main/java/hudson/tasks/test/TestResult.java index 6418df0d..d2c10cbf 100644 --- a/src/main/java/hudson/tasks/test/TestResult.java +++ b/src/main/java/hudson/tasks/test/TestResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -41,11 +41,10 @@ public abstract class TestResult extends TestObject { /** * If the concept of a parent action is important to a subclass, then it should - * provide a non-noop implementation of this method. + * provide a non-noop implementation of this method. * @param action Action that points to the top level test result. */ - public void setParentAction(AbstractTestResultAction action) { - } + public void setParentAction(AbstractTestResultAction action) {} /** * Returns the action that points to the top level test result includes @@ -56,28 +55,26 @@ public void setParentAction(AbstractTestResultAction action) { public AbstractTestResultAction getParentAction() { return getRun().getAction(AbstractTestResultAction.class); } - + /** * Request that the result update its counts of its children. Does not * require a parent action or owner or siblings. Subclasses should - * implement this, unless they are *always* in a tallied state. + * implement this, unless they are *always* in a tallied state. */ - public void tally() { - } - + public void tally() {} + /** * Sets the parent test result * @param parent Parent test result. */ - public void setParent(TestObject parent) { - } + public void setParent(TestObject parent) {} /** * Gets the human readable title of this result object. * * @return the human readable title of this result object. */ - public /* abstract */ String getTitle(){ + public /* abstract */ String getTitle() { return ""; } @@ -120,7 +117,6 @@ public Result getBuildResult() { return 0; } - /** * Gets the total number of skipped tests. */ @@ -128,7 +124,7 @@ public Result getBuildResult() { public /* abstract */ int getSkipCount() { return 0; } - + /** * Gets the counter part of this {@link TestResult} in the previous run. * @@ -136,19 +132,21 @@ public Result getBuildResult() { */ @Override public TestResult getPreviousResult() { - Run b = getRun(); + Run b = getRun(); if (b == null) { return null; } - while(true) { + while (true) { b = b.getPreviousBuild(); - if(b==null) + if (b == null) { return null; + } AbstractTestResultAction r = b.getAction(getParentAction().getClass()); - if(r!=null) { + if (r != null) { TestResult result = r.findCorrespondingResult(this.getId()); - if (result!=null) + if (result != null) { return result; + } } } } @@ -158,7 +156,8 @@ public TestResult getPreviousResult() { * * @return null if no such counter part exists. */ - @Override public TestResult getResultInRun(Run build) { + @Override + public TestResult getResultInRun(Run build) { AbstractTestResultAction tra = build.getAction(getParentAction().getClass()); if (tra == null) { tra = build.getAction(AbstractTestResultAction.class); @@ -174,7 +173,6 @@ public Collection getFailedTests() { return Collections.emptyList(); } - /** * Gets the "children" of this test result that passed * @return the children of this test result, if any, or an empty collection @@ -207,7 +205,7 @@ public int getFailedSince() { * * @return the run when this test started failing. */ - public Run getFailedSinceRun() { + public Run getFailedSinceRun() { return null; } @@ -244,7 +242,7 @@ public String getErrorStackTrace() { * @return the message of the error or failure. */ public String getErrorDetails() { - return ""; + return ""; } public Map getProperties() { @@ -267,23 +265,24 @@ public String toPrettyString() { sb.append("Fail: ").append(this.getFailCount()).append(", "); sb.append("Skipt: ").append(this.getSkipCount()).append(", "); sb.append("Pass: ").append(this.getPassCount()).append(",\n"); - sb.append("Test Result Class: " ).append(this.getClass().getName()).append(" }\n"); - return sb.toString(); + sb.append("Test Result Class: ").append(this.getClass().getName()).append(" }\n"); + return sb.toString(); } /** - * Annotate some text -- what does this do? + * Annotate some text -- what does this do? * @param text Text to use to annotate the actions. * * @return the provided text HTML-escaped. */ public String annotate(String text) { - if (text == null) - return null; + if (text == null) { + return null; + } text = text.replace("&", "&").replace("<", "<"); - for (TestAction action: getTestActions()) { - text = action.annotate(text); + for (TestAction action : getTestActions()) { + text = action.annotate(text); } return text; } diff --git a/src/main/java/hudson/tasks/test/TestResultActionIterable.java b/src/main/java/hudson/tasks/test/TestResultActionIterable.java index 1a167e00..bd685974 100644 --- a/src/main/java/hudson/tasks/test/TestResultActionIterable.java +++ b/src/main/java/hudson/tasks/test/TestResultActionIterable.java @@ -9,7 +9,7 @@ public class TestResultActionIterable implements Iterable>> { private final AbstractTestResultAction latestAction; - + /** * Creates a new iterator that selects action of the given type {@code actionType}. * @@ -19,7 +19,7 @@ public class TestResultActionIterable implements Iterable baseline) { this.latestAction = baseline; } - + @NonNull @Override public Iterator>> iterator() { @@ -48,11 +48,11 @@ public boolean hasNext() { if (initialValue != null) { return true; } - + if (cursor == null) { return false; } - + AbstractTestResultAction previousBuild = cursor.getPreviousResult(AbstractTestResultAction.class, true); return previousBuild != null; } @@ -87,5 +87,4 @@ private AbstractTestResultAction getBuildAction() { return run; } } - } diff --git a/src/main/java/hudson/tasks/test/TestResultDurationChart.java b/src/main/java/hudson/tasks/test/TestResultDurationChart.java index 23dae288..96f72041 100644 --- a/src/main/java/hudson/tasks/test/TestResultDurationChart.java +++ b/src/main/java/hudson/tasks/test/TestResultDurationChart.java @@ -17,8 +17,7 @@ public LinesChartModel create(List results) { return getLinesChartModel(dataset); } - public LinesChartModel create(final Iterable results, - final ChartModelConfiguration configuration) { + public LinesChartModel create(final Iterable results, final ChartModelConfiguration configuration) { TestDurationTrendSeriesBuilder builder = new TestDurationTrendSeriesBuilder(); LinesDataSet dataSet = builder.createDataSet(configuration, results); @@ -28,8 +27,11 @@ public LinesChartModel create(final Iterable results, private LinesChartModel getLinesChartModel(LinesDataSet dataSet) { LinesChartModel model = new LinesChartModel(dataSet); - LineSeries duration = new LineSeries(TestDurationTrendSeriesBuilder.SECONDS, JenkinsPalette.GREEN.normal(), - LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); + LineSeries duration = new LineSeries( + TestDurationTrendSeriesBuilder.SECONDS, + JenkinsPalette.GREEN.normal(), + LineSeries.StackedMode.STACKED, + LineSeries.FilledMode.FILLED); duration.addAll(dataSet.getSeries(TestDurationTrendSeriesBuilder.SECONDS)); model.addSeries(duration); diff --git a/src/main/java/hudson/tasks/test/TestResultParser.java b/src/main/java/hudson/tasks/test/TestResultParser.java index 1f6d8635..2f77cc7b 100644 --- a/src/main/java/hudson/tasks/test/TestResultParser.java +++ b/src/main/java/hudson/tasks/test/TestResultParser.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -55,7 +55,7 @@ public abstract class TestResultParser { */ @Deprecated public String getDisplayName() { - return "Unknown Parser"; + return "Unknown Parser"; } /** @@ -82,9 +82,12 @@ public static ExtensionList all() { } @Deprecated - public TestResult parseResult(String testResultLocations, - Run run, @NonNull FilePath workspace, Launcher launcher, - TaskListener listener) + public TestResult parseResult( + String testResultLocations, + Run run, + @NonNull FilePath workspace, + Launcher launcher, + TaskListener listener) throws InterruptedException, IOException { return parseResult(testResultLocations, run, null, workspace, launcher, listener); } @@ -132,9 +135,13 @@ public TestResult parseResult(String testResultLocations, * will not show a stack trace. * @since 1.22 */ - public TestResult parseResult(String testResultLocations, - Run run, PipelineTestDetails pipelineTestDetails, - @NonNull FilePath workspace, Launcher launcher, TaskListener listener) + public TestResult parseResult( + String testResultLocations, + Run run, + PipelineTestDetails pipelineTestDetails, + @NonNull FilePath workspace, + Launcher launcher, + TaskListener listener) throws InterruptedException, IOException { if (run instanceof AbstractBuild) { return parse(testResultLocations, (AbstractBuild) run, launcher, listener); @@ -144,11 +151,17 @@ public TestResult parseResult(String testResultLocations, } @Deprecated - public TestResult parse(String testResultLocations, - AbstractBuild build, Launcher launcher, - TaskListener listener) + public TestResult parse(String testResultLocations, AbstractBuild build, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { - if (Util.isOverridden(TestResultParser.class, getClass(), "parseResult", String.class, Run.class, FilePath.class, Launcher.class, TaskListener.class)) { + if (Util.isOverridden( + TestResultParser.class, + getClass(), + "parseResult", + String.class, + Run.class, + FilePath.class, + Launcher.class, + TaskListener.class)) { FilePath workspace = build.getWorkspace(); if (workspace == null) { throw new AbortException("no workspace in " + build); diff --git a/src/main/java/hudson/tasks/test/TestResultProjectAction.java b/src/main/java/hudson/tasks/test/TestResultProjectAction.java index 0650d825..6d2daf7b 100644 --- a/src/main/java/hudson/tasks/test/TestResultProjectAction.java +++ b/src/main/java/hudson/tasks/test/TestResultProjectAction.java @@ -64,21 +64,21 @@ public class TestResultProjectAction implements Action, AsyncTrendChart, AsyncCo * Project that owns this action. * @since 1.2-beta-1 */ - public final Job job; + public final Job job; @Deprecated - public final AbstractProject project; + public final AbstractProject project; /** * @since 1.2-beta-1 */ - public TestResultProjectAction(final Job job) { + public TestResultProjectAction(final Job job) { this.job = job; project = job instanceof AbstractProject ? (AbstractProject) job : null; } @Deprecated - public TestResultProjectAction(final AbstractProject project) { + public TestResultProjectAction(final AbstractProject project) { this((Job) project); } @@ -106,10 +106,12 @@ public AbstractTestResultAction getLastTestResultAction() { Nowadays pipeline builds can be failed, even though just a substage failed, whereas other stages do produce test results. Using UNSTABLE is not feasible for this, as that does not mark a build as containing a failure for other systems that list the Jenkins builds externally. */ - Run b = job.getLastBuild(); - while(b!=null) { + Run b = job.getLastBuild(); + while (b != null) { AbstractTestResultAction a = b.getAction(AbstractTestResultAction.class); - if(a!=null && (!b.isBuilding())) return a; + if (a != null && (!b.isBuilding())) { + return a; + } b = b.getPreviousBuild(); } @@ -121,12 +123,14 @@ protected LinesChartModel createChartModel() { return createChartModel(new ChartModelConfiguration(), TestResultTrendChart.PassedColor.BLUE); } - private LinesChartModel createChartModel(ChartModelConfiguration configuration, TestResultTrendChart.PassedColor passedColor) { + private LinesChartModel createChartModel( + ChartModelConfiguration configuration, TestResultTrendChart.PassedColor passedColor) { Run lastCompletedBuild = job.getLastCompletedBuild(); JunitTestResultStorage storage = JunitTestResultStorage.find(); if (!(storage instanceof FileJunitTestResultStorage)) { - TestResultImpl pluggableStorage = storage.load(lastCompletedBuild.getParent().getFullName(), lastCompletedBuild.getNumber()); + TestResultImpl pluggableStorage = + storage.load(lastCompletedBuild.getParent().getFullName(), lastCompletedBuild.getNumber()); List summary = pluggableStorage.getTrendTestResultSummary(); if (summary.isEmpty()) { return new LinesChartModel(); @@ -168,12 +172,13 @@ private TestResultActionIterable createBuildHistory(final Run lastComplete * @deprecated Replaced by echarts in TODO */ @Deprecated - public void doTrend( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException { + public void doTrend(final StaplerRequest req, final StaplerResponse rsp) throws IOException, ServletException { AbstractTestResultAction a = getLastTestResultAction(); - if(a!=null) - a.doGraph(req,rsp); - else + if (a != null) { + a.doGraph(req, rsp); + } else { rsp.setStatus(HttpServletResponse.SC_NOT_FOUND); + } } /** @@ -182,26 +187,28 @@ public void doTrend( final StaplerRequest req, final StaplerResponse rsp ) throw * @deprecated Replaced by echarts in TODO */ @Deprecated - public void doTrendMap( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException { + public void doTrendMap(final StaplerRequest req, final StaplerResponse rsp) throws IOException, ServletException { AbstractTestResultAction a = getLastTestResultAction(); - if(a!=null) - a.doGraphMap(req,rsp); - else + if (a != null) { + a.doGraphMap(req, rsp); + } else { rsp.setStatus(HttpServletResponse.SC_NOT_FOUND); + } } /** * Changes the test result report display mode. */ - public void doFlipTrend( final StaplerRequest req, final StaplerResponse rsp ) throws IOException, ServletException { + public void doFlipTrend(final StaplerRequest req, final StaplerResponse rsp) throws IOException, ServletException { boolean failureOnly = false; // check the current preference value Cookie[] cookies = req.getCookies(); - if(cookies!=null) { + if (cookies != null) { for (Cookie cookie : cookies) { - if(cookie.getName().equals(FAILURE_ONLY_COOKIE)) + if (cookie.getName().equals(FAILURE_ONLY_COOKIE)) { failureOnly = Boolean.parseBoolean(cookie.getValue()); + } } } @@ -209,11 +216,11 @@ public void doFlipTrend( final StaplerRequest req, final StaplerResponse rsp ) t failureOnly = !failureOnly; // set the updated value - Cookie cookie = new Cookie(FAILURE_ONLY_COOKIE,String.valueOf(failureOnly)); + Cookie cookie = new Cookie(FAILURE_ONLY_COOKIE, String.valueOf(failureOnly)); List anc = req.getAncestors(); - Ancestor a = anc.get(anc.size()-2); + Ancestor a = anc.get(anc.size() - 2); cookie.setPath(a.getUrl()); // just for this project - cookie.setMaxAge(60*60*24*365); // 1 year + cookie.setMaxAge(60 * 60 * 24 * 365); // 1 year rsp.addCookie(cookie); // back to the project page @@ -222,7 +229,8 @@ public void doFlipTrend( final StaplerRequest req, final StaplerResponse rsp ) t private static final String FAILURE_ONLY_COOKIE = "TestResultAction_failureOnly"; - @Override @Deprecated + @Override + @Deprecated public String getBuildTrendModel() { return new JacksonFacade().toJson(createChartModel()); } @@ -230,7 +238,9 @@ public String getBuildTrendModel() { @JavaScriptMethod @Override public String getConfigurableBuildTrendModel(final String configuration) { - TestResultTrendChart.PassedColor useBlue = JACKSON_FACADE.getBoolean(configuration, "useBlue", false) ? TestResultTrendChart.PassedColor.BLUE : TestResultTrendChart.PassedColor.GREEN; + TestResultTrendChart.PassedColor useBlue = JACKSON_FACADE.getBoolean(configuration, "useBlue", false) + ? TestResultTrendChart.PassedColor.BLUE + : TestResultTrendChart.PassedColor.GREEN; return new JacksonFacade().toJson(createChartModel(ChartModelConfiguration.fromJson(configuration), useBlue)); } diff --git a/src/main/java/hudson/tasks/test/TestResultTrendChart.java b/src/main/java/hudson/tasks/test/TestResultTrendChart.java index 2af706b3..d4dd29fa 100644 --- a/src/main/java/hudson/tasks/test/TestResultTrendChart.java +++ b/src/main/java/hudson/tasks/test/TestResultTrendChart.java @@ -10,7 +10,10 @@ import java.util.List; public class TestResultTrendChart { - enum PassedColor {GREEN, BLUE} + enum PassedColor { + GREEN, + BLUE + } public LinesChartModel create(final List results) { return create(results, PassedColor.BLUE); @@ -27,7 +30,9 @@ public LinesChartModel create(@NonNull final Iterable results, final ChartModelC return create(results, configuration, PassedColor.GREEN); } - public LinesChartModel create(@NonNull final Iterable results, final ChartModelConfiguration configuration, + public LinesChartModel create( + @NonNull final Iterable results, + final ChartModelConfiguration configuration, final PassedColor passedColor) { TestResultTrendSeriesBuilder builder = new TestResultTrendSeriesBuilder(); LinesDataSet dataSet = builder.createDataSet(configuration, results); @@ -35,13 +40,12 @@ public LinesChartModel create(@NonNull final Iterable results, final ChartModelC return getLinesChartModel(dataSet, passedColor); } - public LinesChartModel createFromTestObject(final Iterable results, - final ChartModelConfiguration configuration) { + public LinesChartModel createFromTestObject(final Iterable results, final ChartModelConfiguration configuration) { return createFromTestObject(results, configuration, PassedColor.GREEN); } - public LinesChartModel createFromTestObject(final Iterable results, final ChartModelConfiguration configuration, - final PassedColor passedColor) { + public LinesChartModel createFromTestObject( + final Iterable results, final ChartModelConfiguration configuration, final PassedColor passedColor) { TestObjectTrendSeriesBuilder builder = new TestObjectTrendSeriesBuilder(); LinesDataSet dataSet = builder.createDataSet(configuration, results); @@ -50,19 +54,21 @@ public LinesChartModel createFromTestObject(final Iterable results, final ChartM private LinesChartModel getLinesChartModel(final LinesDataSet dataSet, final PassedColor passedColor) { LinesChartModel model = new LinesChartModel(dataSet); - LineSeries passed = new LineSeries("Passed", + LineSeries passed = new LineSeries( + "Passed", passedColor == PassedColor.BLUE ? JenkinsPalette.BLUE.normal() : JenkinsPalette.GREEN.normal(), - LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); + LineSeries.StackedMode.STACKED, + LineSeries.FilledMode.FILLED); passed.addAll(dataSet.getSeries(TestResultTrendSeriesBuilder.PASSED_KEY)); model.addSeries(passed); - LineSeries skipped = new LineSeries("Skipped", JenkinsPalette.GREY.normal(), - LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); + LineSeries skipped = new LineSeries( + "Skipped", JenkinsPalette.GREY.normal(), LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); skipped.addAll(dataSet.getSeries(TestResultTrendSeriesBuilder.SKIPPED_KEY)); model.addSeries(skipped); - LineSeries failed = new LineSeries("Failed", JenkinsPalette.RED.normal(), - LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); + LineSeries failed = new LineSeries( + "Failed", JenkinsPalette.RED.normal(), LineSeries.StackedMode.STACKED, LineSeries.FilledMode.FILLED); failed.addAll(dataSet.getSeries(TestResultTrendSeriesBuilder.FAILED_KEY)); model.addSeries(failed); diff --git a/src/main/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisher.java b/src/main/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisher.java index e0ac65c3..e477d876 100644 --- a/src/main/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisher.java +++ b/src/main/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisher.java @@ -28,7 +28,8 @@ public class JUnitChecksPublisher { private final TestResult result; private final TestResultSummary summary; - public JUnitChecksPublisher(final Run run, final String checksName, final TestResult result, final TestResultSummary summary) { + public JUnitChecksPublisher( + final Run run, final String checksName, final TestResult result, final TestResultSummary summary) { this.run = run; this.checksName = checksName; this.result = result; @@ -63,14 +64,15 @@ private String extractChecksText(String testsURL) { if (summary.getFailCount() > 0) { List failedTests = result.getFailedTests(); - for (CaseResult failedTest: failedTests) { + for (CaseResult failedTest : failedTests) { String testReport = mapFailedTestToTestReport(failedTest); int messageSize = testReport.length() + builder.toString().length(); // to ensure text size is withing check API message limit - if (messageSize > (MAX_MSG_SIZE_TO_CHECKS_API - 1024)){ + if (messageSize > (MAX_MSG_SIZE_TO_CHECKS_API - 1024)) { builder.append("\n") .append("more test results are not shown here, view them on [Jenkins](") - .append(testsURL).append(")"); + .append(testsURL) + .append(")"); break; } builder.append(testReport); @@ -82,14 +84,17 @@ private String extractChecksText(String testsURL) { private String mapFailedTestToTestReport(CaseResult failedTest) { StringBuilder builder = new StringBuilder(); - builder.append("## `").append(failedTest.getTransformedFullDisplayName().trim()).append("`") + builder.append("## `") + .append(failedTest.getTransformedFullDisplayName().trim()) + .append("`") .append("\n"); - if (failedTest.getErrorDetails() != null && !failedTest.getErrorDetails().trim().isEmpty()) { - builder.append(codeTextFencedBlock(failedTest.getErrorDetails())) - .append("\n"); + if (failedTest.getErrorDetails() != null + && !failedTest.getErrorDetails().trim().isEmpty()) { + builder.append(codeTextFencedBlock(failedTest.getErrorDetails())).append("\n"); } - if (failedTest.getErrorStackTrace() != null && !failedTest.getErrorStackTrace().trim().isEmpty()) { + if (failedTest.getErrorStackTrace() != null + && !failedTest.getErrorStackTrace().trim().isEmpty()) { builder.append("

Stack trace\n") .append(codeTextFencedBlock(failedTest.getErrorStackTrace())) .append("
\n"); @@ -109,7 +114,7 @@ private String mapFailedTestToTestReport(CaseResult failedTest) { builder.append("\n"); return builder.toString(); } - + private String codeTextFencedBlock(String body) { return "\n```text\n" + body.trim() + "\n```\n"; } @@ -147,7 +152,6 @@ private String extractChecksTitle() { builder.append("passed: ").append(summary.getPassCount()); } - return builder.toString(); } } diff --git a/src/main/java/io/jenkins/plugins/junit/storage/FileJunitTestResultStorage.java b/src/main/java/io/jenkins/plugins/junit/storage/FileJunitTestResultStorage.java index d19fb4a5..5c1fe663 100644 --- a/src/main/java/io/jenkins/plugins/junit/storage/FileJunitTestResultStorage.java +++ b/src/main/java/io/jenkins/plugins/junit/storage/FileJunitTestResultStorage.java @@ -13,8 +13,7 @@ public class FileJunitTestResultStorage extends JunitTestResultStorage { @DataBoundConstructor - public FileJunitTestResultStorage() { - } + public FileJunitTestResultStorage() {} @Override public RemotePublisher createRemotePublisher(Run build) throws IOException { @@ -34,6 +33,5 @@ public static class DescriptorImpl extends JunitTestResultStorageDescriptor { public String getDisplayName() { return Messages.FileJunitTestResultStorage_displayName(); } - } } diff --git a/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorage.java b/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorage.java index a54c21df..735740f1 100644 --- a/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorage.java +++ b/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorage.java @@ -39,12 +39,13 @@ * Allows test results to be saved and loaded from an external storage service. */ @Restricted(Beta.class) -public abstract class JunitTestResultStorage extends AbstractDescribableImpl implements ExtensionPoint { +public abstract class JunitTestResultStorage extends AbstractDescribableImpl + implements ExtensionPoint { /** * Runs during {@link JUnitParser#summarizeResult}. */ - public abstract RemotePublisher createRemotePublisher(Run build) throws IOException; + public abstract RemotePublisher createRemotePublisher(Run build) throws IOException; /** * Remotable hook to perform test result publishing. @@ -60,5 +61,4 @@ public interface RemotePublisher extends SerializableOnlyOverRemoting { public static JunitTestResultStorage find() { return JunitTestResultStorageConfiguration.get().getStorage(); } - } diff --git a/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorageConfiguration.java b/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorageConfiguration.java index 1fe1ebd2..77fd40ca 100644 --- a/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorageConfiguration.java +++ b/src/main/java/io/jenkins/plugins/junit/storage/JunitTestResultStorageConfiguration.java @@ -16,7 +16,7 @@ @Restricted(Beta.class) @Symbol("junitTestResultStorage") public class JunitTestResultStorageConfiguration extends GlobalConfiguration { - + private JunitTestResultStorage storage = new FileJunitTestResultStorage(); @DataBoundConstructor diff --git a/src/main/java/io/jenkins/plugins/junit/storage/TestResultImpl.java b/src/main/java/io/jenkins/plugins/junit/storage/TestResultImpl.java index adbf1d68..1eb4878b 100644 --- a/src/main/java/io/jenkins/plugins/junit/storage/TestResultImpl.java +++ b/src/main/java/io/jenkins/plugins/junit/storage/TestResultImpl.java @@ -48,16 +48,27 @@ @Restricted(Beta.class) public interface TestResultImpl { int getFailCount(); + int getSkipCount(); + int getPassCount(); + int getTotalCount(); + List getFailedTests(); + List getFailedTestsByPackage(String packageName); + List getSkippedTests(); + List getSkippedTestsByPackage(String packageName); + List getPassedTests(); + List getPassedTestsByPackage(String packageName); + PackageResult getPackageResult(String packageName); + List getAllPackageResults(); /** @@ -80,7 +91,7 @@ public interface TestResultImpl { * @return count of builds with tests results */ int getCountOfBuildsWithTestResults(); - + Run getFailedSinceRun(CaseResult caseResult); @CheckForNull @@ -108,13 +119,13 @@ public interface TestResultImpl { */ @CheckForNull TestResult getPreviousResult(); - SuiteResult getSuite(String name); + SuiteResult getSuite(String name); default Collection getSuites() { return Collections.emptyList(); - }; - + } + ; float getTotalTestDuration(); } diff --git a/src/test/java/hudson/tasks/junit/CaseResultTest.java b/src/test/java/hudson/tasks/junit/CaseResultTest.java index 03c043fa..ccd985e1 100644 --- a/src/test/java/hudson/tasks/junit/CaseResultTest.java +++ b/src/test/java/hudson/tasks/junit/CaseResultTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Yahoo! Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -61,22 +61,22 @@ * @author Kohsuke Kawaguchi */ public class CaseResultTest { -// /** -// * Verifies that Hudson can capture the stdout/stderr output from Maven surefire. -// */ -// public void testSurefireOutput() throws Exception { -// setJavaNetCredential(); -// configureDefaultMaven(); -// -// MavenModuleSet p = createMavenProject(); -// p.setScm(new SubversionSCM(".../hudson/test-projects/junit-failure@16411")); -// MavenModuleSetBuild b = assertBuildStatus(UNSTABLE,p.scheduleBuild2(0).get()); -// AbstractTestResultAction t = b.getAction(AbstractTestResultAction.class); -// assertSame(1,t.getFailCount()); -// CaseResult tc = t.getFailedTests().get(0); -// assertTrue(tc.getStderr().contains("stderr")); -// assertTrue(tc.getStdout().contains("stdout")); -// } + // /** + // * Verifies that Hudson can capture the stdout/stderr output from Maven surefire. + // */ + // public void testSurefireOutput() throws Exception { + // setJavaNetCredential(); + // configureDefaultMaven(); + // + // MavenModuleSet p = createMavenProject(); + // p.setScm(new SubversionSCM(".../hudson/test-projects/junit-failure@16411")); + // MavenModuleSetBuild b = assertBuildStatus(UNSTABLE,p.scheduleBuild2(0).get()); + // AbstractTestResultAction t = b.getAction(AbstractTestResultAction.class); + // assertSame(1,t.getFailCount()); + // CaseResult tc = t.getFailedTests().get(0); + // assertTrue(tc.getStderr().contains("stderr")); + // assertTrue(tc.getStdout().contains("stdout")); + // } @Rule public final JenkinsRule rule = new JenkinsRule(); @@ -86,33 +86,27 @@ public class CaseResultTest { public void testIssue20090516() throws Exception { FreeStyleBuild b = configureTestBuild(null); TestResult tr = b.getAction(TestResultAction.class).getResult(); - assertEquals(3,tr.getFailedTests().size()); + assertEquals(3, tr.getFailedTests().size()); // Alphabetic order to ensure a stable list regardless of parallel execution or multiple result suites. CaseResult cr = tr.getFailedTests().get(2); - assertEquals("org.twia.vendor.VendorManagerTest",cr.getClassName()); - assertEquals("testGetVendorFirmKeyForVendorRep",cr.getName()); + assertEquals("org.twia.vendor.VendorManagerTest", cr.getClassName()); + assertEquals("testGetVendorFirmKeyForVendorRep", cr.getName()); // piggy back tests for annotate methods - assertOutput(cr,"plain text", "plain text"); - assertOutput(cr,"line #1\nhttp://nowhere.net/\nline #2\n", - "line #1\nhttp://nowhere.net/\nline #2\n"); - assertOutput(cr,"failed; see http://nowhere.net/", - "failed; see http://nowhere.net/"); - assertOutput(cr,"failed (see http://nowhere.net/)", - "failed (see http://nowhere.net/)"); - assertOutput(cr,"http://nowhere.net/ - failed: http://elsewhere.net/", - "http://nowhere.net/ - failed: " + - "http://elsewhere.net/"); - assertOutput(cr,"https://nowhere.net/", - "https://nowhere.net/"); - assertOutput(cr,"stuffhttp://nowhere.net/", "stuffhttp://nowhere.net/"); - assertOutput(cr,"a < b && c < d", "a < b && c < d"); - assertOutput(cr,"see ", - "see <http://nowhere.net/>"); - assertOutput(cr,"http://google.com/?q=stuff&lang=en", - "http://google.com/?q=stuff&lang=en"); - assertOutput(cr,"http://localhost:8080/stuff/", - "http://localhost:8080/stuff/"); + assertOutput(cr, "plain text", "plain text"); + assertOutput(cr, "line #1\nhttp://nowhere.net/\nline #2\n", "line #1\nhttp://nowhere.net/\nline #2\n"); + assertOutput(cr, "failed; see http://nowhere.net/", "failed; see http://nowhere.net/"); + assertOutput(cr, "failed (see http://nowhere.net/)", "failed (see http://nowhere.net/)"); + assertOutput( + cr, + "http://nowhere.net/ - failed: http://elsewhere.net/", + "http://nowhere.net/ - failed: " + "http://elsewhere.net/"); + assertOutput(cr, "https://nowhere.net/", "https://nowhere.net/"); + assertOutput(cr, "stuffhttp://nowhere.net/", "stuffhttp://nowhere.net/"); + assertOutput(cr, "a < b && c < d", "a < b && c < d"); + assertOutput(cr, "see ", "see <http://nowhere.net/>"); + assertOutput(cr, "http://google.com/?q=stuff&lang=en", "http://google.com/?q=stuff&lang=en"); + assertOutput(cr, "http://localhost:8080/stuff/", "http://localhost:8080/stuff/"); } /** @@ -120,18 +114,18 @@ public void testIssue20090516() throws Exception { */ @Test public void noPopUpsWhenExpandingATest() throws Exception { - Assume.assumeFalse(Functions.isWindows()); - + Assume.assumeFalse(Functions.isWindows()); + FreeStyleProject project = rule.createFreeStyleProject("escape_test"); - //Shell command which includes a vulnerability + // Shell command which includes a vulnerability Shell shell = new Shell("echo \"java.lang.NullPointerException " - + "\" > junit.xml"); + + "errors=\\\"1\\\" failures=\\\"0\\\" hostname=\\\"whocares\\\" " + + "name=\\\"nobody\\\" tests=\\\"1\\\" time=\\\"0.016\\\" " + + "timestamp=\\\"2023-01-01T15:42:30\\\">java.lang.NullPointerException " + + "\" > junit.xml"); // Schedule a build of the project, passing in the shell command project.getBuildersList().add(shell); @@ -146,8 +140,8 @@ public void noPopUpsWhenExpandingATest() throws Exception { webClient.setAlertHandler(alerter); HtmlPage page = webClient.goTo("job/escape_test/1/testReport/"); - //The Xpath here is for the '+' on the page, which when clicked expands the test - //the element we want to test is the first icon-sm in the list from the page + // The Xpath here is for the '+' on the page, which when clicked expands the test + // the element we want to test is the first icon-sm in the list from the page List elements = page.getByXPath("//*[@class='icon-sm']"); elements.get(0).click(); webClient.waitForBackgroundJavaScript(2000); @@ -156,6 +150,7 @@ public void noPopUpsWhenExpandingATest() throws Exception { static class Alerter implements AlertHandler { List messages = Collections.synchronizedList(new ArrayList<>()); + @Override public void handleAlert(final Page page, final String message) { messages.add(message); @@ -170,40 +165,47 @@ public void handleAlert(final Page page, final String message) { public void testFreestyleErrorMsgAndStacktraceRender() throws Exception { FreeStyleBuild b = configureTestBuild("render-test"); TestResult tr = b.getAction(TestResultAction.class).getResult(); - assertEquals(3,tr.getFailedTests().size()); + assertEquals(3, tr.getFailedTests().size()); CaseResult cr = tr.getFailedTests().get(1); - assertEquals("org.twia.vendor.VendorManagerTest",cr.getClassName()); - assertEquals("testGetRevokedClaimsForAdjustingFirm",cr.getName()); - assertNotNull("Error details should not be null", cr.getErrorDetails()); - assertNotNull("Error stacktrace should not be null", cr.getErrorStackTrace()); - - String testUrl = cr.getRelativePathFrom(tr); - - HtmlPage page = rule.createWebClient().goTo("job/render-test/1/testReport/" + testUrl); - - HtmlElement errorMsg = (HtmlElement) page.getByXPath("//h3[text()='Error Message']/following-sibling::*").get(0); - - assertEquals(cr.annotate(cr.getErrorDetails()).replaceAll("<", "<"), errorMsg.getTextContent()); - HtmlElement errorStackTrace = (HtmlElement) page.getByXPath("//h3[text()='Stacktrace']/following-sibling::*").get(0); - // Have to do some annoying replacing here to get the same text Jelly produces in the end. - assertEquals(cr.annotate(cr.getErrorStackTrace()).replaceAll("<", "<").replace("\r\n", "\n"), - errorStackTrace.getTextContent()); + assertEquals("org.twia.vendor.VendorManagerTest", cr.getClassName()); + assertEquals("testGetRevokedClaimsForAdjustingFirm", cr.getName()); + assertNotNull("Error details should not be null", cr.getErrorDetails()); + assertNotNull("Error stacktrace should not be null", cr.getErrorStackTrace()); + + String testUrl = cr.getRelativePathFrom(tr); + + HtmlPage page = rule.createWebClient().goTo("job/render-test/1/testReport/" + testUrl); + + HtmlElement errorMsg = (HtmlElement) page.getByXPath("//h3[text()='Error Message']/following-sibling::*") + .get(0); + + assertEquals(cr.annotate(cr.getErrorDetails()).replaceAll("<", "<"), errorMsg.getTextContent()); + HtmlElement errorStackTrace = (HtmlElement) page.getByXPath("//h3[text()='Stacktrace']/following-sibling::*") + .get(0); + // Have to do some annoying replacing here to get the same text Jelly produces in the end. + assertEquals( + cr.annotate(cr.getErrorStackTrace()).replaceAll("<", "<").replace("\r\n", "\n"), + errorStackTrace.getTextContent()); } - + /** * Verify fields show up at the correct visibility in the remote API */ + private static final String[] MAX_VISIBILITY_FIELDS = {"name"}; - private static final String[] MAX_VISIBILITY_FIELDS = { "name" }; - private static final String[] REDUCED_VISIBILITY_FIELDS = { "stdout", "stderr", "errorStackTrace", "errorDetails" }; - private static final String[] OTHER_FIELDS = { "duration", "className", "failedSince", "age", "skipped", "status" }; + private static final String[] REDUCED_VISIBILITY_FIELDS = {"stdout", "stderr", "errorStackTrace", "errorDetails"}; + private static final String[] OTHER_FIELDS = {"duration", "className", "failedSince", "age", "skipped", "status"}; - @Email("http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") + @Email( + "http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") @Test public void testRemoteApiDefaultVisibility() throws Exception { FreeStyleBuild b = configureTestBuild("test-remoteapi"); - XmlPage page = (XmlPage)rule.createWebClient().goTo("job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml","application/xml"); + XmlPage page = (XmlPage) rule.createWebClient() + .goTo( + "job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml", + "application/xml"); int found = 0; @@ -216,13 +218,17 @@ public void testRemoteApiDefaultVisibility() throws Exception { found = page.getByXPath(composeXPath(OTHER_FIELDS)).size(); assertTrue("Should have found an element, but found " + found, found > 0); } - - @Email("http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") + + @Email( + "http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") @Test public void testRemoteApiNoDetails() throws Exception { FreeStyleBuild b = configureTestBuild("test-remoteapi"); - XmlPage page = (XmlPage)rule.createWebClient().goTo("job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml?depth=-1","application/xml"); + XmlPage page = (XmlPage) rule.createWebClient() + .goTo( + "job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml?depth=-1", + "application/xml"); int found = 0; @@ -234,14 +240,18 @@ public void testRemoteApiNoDetails() throws Exception { found = page.getByXPath(composeXPath(OTHER_FIELDS)).size(); assertTrue("Should have found an element, but found " + found, found > 0); - } - - @Email("http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") + } + + @Email( + "http://jenkins.361315.n4.nabble.com/Change-remote-API-visibility-for-CaseResult-getStdout-getStderr-td395102.html") @Test public void testRemoteApiNameOnly() throws Exception { FreeStyleBuild b = configureTestBuild("test-remoteapi"); - XmlPage page = (XmlPage)rule.createWebClient().goTo("job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml?depth=-10","application/xml"); + XmlPage page = (XmlPage) rule.createWebClient() + .goTo( + "job/test-remoteapi/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/api/xml?depth=-10", + "application/xml"); int found = 0; @@ -264,63 +274,69 @@ public void testRemoteApiNameOnly() throws Exception { public void testContentType() throws Exception { configureTestBuild("foo"); JenkinsRule.WebClient wc = rule.createWebClient(); - wc.goTo("job/foo/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/","text/html"); + wc.goTo("job/foo/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/", "text/html"); - wc.goTo("job/foo/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/summary","text/plain"); + wc.goTo("job/foo/1/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/summary", "text/plain"); } /** - * Execute twice a failing test and make sure its failing age is 2 - */ + * Execute twice a failing test and make sure its failing age is 2 + */ @Issue("JENKINS-30413") @Test public void testAge() throws Exception { String projectName = "tr-age-test"; String testResultResourceFile = "JENKINS-30413.xml"; - //Create a job: + // Create a job: FreeStyleProject p = rule.createFreeStyleProject(projectName); p.getPublishersList().add(new JUnitResultArchiver("*.xml")); // add builder copying test result file p.getBuildersList().add(new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { FilePath junitFile = build.getWorkspace().child("junit.xml"); junitFile.copyFrom(getClass().getResource(testResultResourceFile)); // sadly this can be flaky for 1ms.... (but hey changing to nano even in core might complicated :)) - junitFile.touch(System.currentTimeMillis()+1L); + junitFile.touch(System.currentTimeMillis() + 1L); return true; } }); - //First build execution + // First build execution { - FreeStyleBuild b1 = rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); + FreeStyleBuild b1 = + rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); - //First build result analysis: + // First build result analysis: TestResult tr = b1.getAction(TestResultAction.class).getResult(); assertEquals(1, tr.getFailedTests().size()); CaseResult cr = tr.getFailedTests().get(0); - assertEquals(1, cr.getAge()); //First execution, failing test age is expected to be 1 + assertEquals(1, cr.getAge()); // First execution, failing test age is expected to be 1 } - //Second build execution + // Second build execution { - FreeStyleBuild b2 = rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); + FreeStyleBuild b2 = + rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); - //Second build result analysis: + // Second build result analysis: TestResult tr2 = b2.getAction(TestResultAction.class).getResult(); assertEquals(1, tr2.getFailedTests().size()); CaseResult cr2 = tr2.getFailedTests().get(0); - assertEquals(2, cr2.getAge()); //At second execution, failing test age should be 2 + assertEquals(2, cr2.getAge()); // At second execution, failing test age should be 2 } } private FreeStyleBuild configureTestBuild(String projectName) throws Exception { - FreeStyleProject p = projectName == null ? rule.createFreeStyleProject() : rule.createFreeStyleProject(projectName); + FreeStyleProject p = + projectName == null ? rule.createFreeStyleProject() : rule.createFreeStyleProject(projectName); p.getBuildersList().add(new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - build.getWorkspace().child("junit.xml").copyFrom( - getClass().getResource("junit-report-20090516.xml")); + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { + build.getWorkspace().child("junit.xml").copyFrom(getClass().getResource("junit-report-20090516.xml")); return true; } }); @@ -332,7 +348,10 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen @Test public void emptyName() throws Exception { FreeStyleProject p = rule.createFreeStyleProject(); - rule.jenkins.getWorkspaceFor(p).child("x.xml").write("", null); + rule.jenkins + .getWorkspaceFor(p) + .child("x.xml") + .write("", null); p.getBuildersList().add(new TouchBuilder()); p.getPublishersList().add(new JUnitResultArchiver("x.xml")); rule.buildAndAssertSuccess(p); @@ -346,22 +365,25 @@ public void testProperties() throws Exception { FreeStyleProject p = rule.createFreeStyleProject(projectName); p.getPublishersList().add(new JUnitResultArchiver("*.xml", false, true, null, 1.0)); p.getBuildersList().add(new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { FilePath junitFile = build.getWorkspace().child("junit.xml"); junitFile.copyFrom(getClass().getResource(testResultResourceFile)); // sadly this can be flaky for 1ms.... (but hey changing to nano even in core might complicated :)) - junitFile.touch(System.currentTimeMillis()+1L); + junitFile.touch(System.currentTimeMillis() + 1L); return true; } }); - FreeStyleBuild b = rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); + FreeStyleBuild b = + rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); TestResult tr = b.getAction(TestResultAction.class).getResult(); assertEquals(1, tr.getSuites().size()); SuiteResult sr = tr.getSuite("io.jenkins.example.with.properties"); - Map props = sr.getProperties(); + Map props = sr.getProperties(); assertEquals("value1", props.get("prop1")); String[] lines = props.get("multiline").split("\n"); assertEquals("", lines[0]); @@ -385,22 +407,25 @@ public void testDontKeepProperties() throws Exception { FreeStyleProject p = rule.createFreeStyleProject(projectName); p.getPublishersList().add(new JUnitResultArchiver("*.xml", false, false, null, 1.0)); p.getBuildersList().add(new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { FilePath junitFile = build.getWorkspace().child("junit.xml"); junitFile.copyFrom(getClass().getResource(testResultResourceFile)); // sadly this can be flaky for 1ms.... (but hey changing to nano even in core might complicated :)) - junitFile.touch(System.currentTimeMillis()+1L); + junitFile.touch(System.currentTimeMillis() + 1L); return true; } }); - FreeStyleBuild b = rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); + FreeStyleBuild b = + rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); TestResult tr = b.getAction(TestResultAction.class).getResult(); assertEquals(1, tr.getSuites().size()); SuiteResult sr = tr.getSuite("io.jenkins.example.with.properties"); - Map props = sr.getProperties(); + Map props = sr.getProperties(); assertEquals(0, props.size()); CaseResult cr; @@ -412,8 +437,8 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen private String composeXPath(String[] fields) throws Exception { StringBuilder tmp = new StringBuilder(100); - for ( String f : fields ) { - if (tmp.length() > 0 ) { + for (String f : fields) { + if (tmp.length() > 0) { tmp.append("|"); } tmp.append("//caseResult/"); @@ -422,9 +447,8 @@ private String composeXPath(String[] fields) throws Exception { return tmp.toString(); } - + private void assertOutput(CaseResult cr, String in, String out) throws Exception { assertEquals(out, cr.annotate(in)); } - } diff --git a/src/test/java/hudson/tasks/junit/CaseResultUnitTest.java b/src/test/java/hudson/tasks/junit/CaseResultUnitTest.java index ce25c9b7..1ff5b399 100644 --- a/src/test/java/hudson/tasks/junit/CaseResultUnitTest.java +++ b/src/test/java/hudson/tasks/junit/CaseResultUnitTest.java @@ -35,10 +35,9 @@ @For(CaseResult.class) public class CaseResultUnitTest { - - public CaseResultUnitTest() { - } - + + public CaseResultUnitTest() {} + @Issue("JENKINS-6824") @Test public void testLocalizationOfStatus() throws Exception { @@ -58,5 +57,4 @@ public void testLocalizationOfStatus() throws Exception { LocaleProvider.setProvider(old); } } - } diff --git a/src/test/java/hudson/tasks/junit/ClassResultTest.java b/src/test/java/hudson/tasks/junit/ClassResultTest.java index 80a7d756..58241d99 100644 --- a/src/test/java/hudson/tasks/junit/ClassResultTest.java +++ b/src/test/java/hudson/tasks/junit/ClassResultTest.java @@ -7,40 +7,39 @@ public class ClassResultTest { - @Test - public void testFindCorrespondingResult() { - ClassResult classResult = new ClassResult(null, "com.example.ExampleTest"); - - CaseResult caseResult = new CaseResult(null, "testCase", null); - - classResult.add(caseResult); - - TestResult result = classResult.findCorrespondingResult("extraprefix.com.example.ExampleTest.testCase"); - assertEquals(caseResult, result); - } - - @Test - public void testFindCorrespondingResultWhereClassResultNameIsNotSubstring() { - ClassResult classResult = new ClassResult(null, "aaaa"); - - CaseResult caseResult = new CaseResult(null, "tc_bbbb", null); - - classResult.add(caseResult); - - TestResult result = classResult.findCorrespondingResult("tc_bbbb"); - assertEquals(caseResult, result); - } - - @Test - public void testFindCorrespondingResultWhereClassResultNameIsLastInCaseResultName() { - ClassResult classResult = new ClassResult(null, "aaaa"); - - CaseResult caseResult = new CaseResult(null, "tc_aaaa", null); - - classResult.add(caseResult); - - TestResult result = classResult.findCorrespondingResult("tc_aaaa"); - assertEquals(caseResult, result); - } + @Test + public void testFindCorrespondingResult() { + ClassResult classResult = new ClassResult(null, "com.example.ExampleTest"); + CaseResult caseResult = new CaseResult(null, "testCase", null); + + classResult.add(caseResult); + + TestResult result = classResult.findCorrespondingResult("extraprefix.com.example.ExampleTest.testCase"); + assertEquals(caseResult, result); + } + + @Test + public void testFindCorrespondingResultWhereClassResultNameIsNotSubstring() { + ClassResult classResult = new ClassResult(null, "aaaa"); + + CaseResult caseResult = new CaseResult(null, "tc_bbbb", null); + + classResult.add(caseResult); + + TestResult result = classResult.findCorrespondingResult("tc_bbbb"); + assertEquals(caseResult, result); + } + + @Test + public void testFindCorrespondingResultWhereClassResultNameIsLastInCaseResultName() { + ClassResult classResult = new ClassResult(null, "aaaa"); + + CaseResult caseResult = new CaseResult(null, "tc_aaaa", null); + + classResult.add(caseResult); + + TestResult result = classResult.findCorrespondingResult("tc_aaaa"); + assertEquals(caseResult, result); + } } diff --git a/src/test/java/hudson/tasks/junit/CustomColumnsTest.java b/src/test/java/hudson/tasks/junit/CustomColumnsTest.java index 84486efd..763f68a6 100644 --- a/src/test/java/hudson/tasks/junit/CustomColumnsTest.java +++ b/src/test/java/hudson/tasks/junit/CustomColumnsTest.java @@ -58,8 +58,8 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } @SafeVarargs - private void verifyThatTableContainsExpectedValues(String pathToPage, String tableId, String headerName, - Pair... rowValues) throws Exception { + private void verifyThatTableContainsExpectedValues( + String pathToPage, String tableId, String headerName, Pair... rowValues) throws Exception { JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(jenkins); HtmlPage projectPage = wc.getPage(project); @@ -68,45 +68,64 @@ private void verifyThatTableContainsExpectedValues(String pathToPage, String tab jenkins.assertGoodStatus(classReportPage); HtmlTable testResultTable = (HtmlTable) classReportPage.getFirstByXPath("//table[@id='" + tableId + "']"); - List headerRowCells = testResultTable.getHeader().getRows().get(0).getCells(); + List headerRowCells = + testResultTable.getHeader().getRows().get(0).getCells(); int numberOfColumns = headerRowCells.size(); assertEquals(headerName, headerRowCells.get(numberOfColumns - 1).asNormalizedText()); for (int x = 0; x < rowValues.length; x++) { - List bodyRowCells = testResultTable.getBodies().get(0).getRows().get(x).getCells(); + List bodyRowCells = + testResultTable.getBodies().get(0).getRows().get(x).getCells(); assertThat(bodyRowCells.get(0).asNormalizedText(), CoreMatchers.containsString(rowValues[x].getLeft())); - assertEquals(rowValues[x].getRight(), bodyRowCells.get(numberOfColumns - 1).asNormalizedText()); + assertEquals( + rowValues[x].getRight(), + bodyRowCells.get(numberOfColumns - 1).asNormalizedText()); } } @Test public void verifyThatCustomColumnIsAddedToTheTestsTableOnTheClassResultPage() throws Exception { - verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/AnExampleTestClass/", - "testresult", "ROT13 for cases on class page", Pair.of("testCaseA", "grfgPnfrN for case"), Pair.of( - "testCaseZ", "grfgPnfrM for case")); + verifyThatTableContainsExpectedValues( + "/lastBuild/testReport/junit/io.jenkins.example/AnExampleTestClass/", + "testresult", + "ROT13 for cases on class page", + Pair.of("testCaseA", "grfgPnfrN for case"), + Pair.of("testCaseZ", "grfgPnfrM for case")); } @Test public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnThePackageResultPage() throws Exception { - verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "failedtestresult", - "ROT13 for failed cases on package page", Pair.of("testCaseA", "grfgPnfrN for case")); + verifyThatTableContainsExpectedValues( + "/lastBuild/testReport/junit/io.jenkins.example/", + "failedtestresult", + "ROT13 for failed cases on package page", + Pair.of("testCaseA", "grfgPnfrN for case")); } @Test public void verifyThatCustomColumnIsAddedToTheClassesTableOnThePackageResultPage() throws Exception { - verifyThatTableContainsExpectedValues("/lastBuild/testReport/junit/io.jenkins.example/", "testresult", - "ROT13 for all classes on package page", Pair.of("AnExampleTestClass", "NaRknzcyrGrfgPynff for class")); + verifyThatTableContainsExpectedValues( + "/lastBuild/testReport/junit/io.jenkins.example/", + "testresult", + "ROT13 for all classes on package page", + Pair.of("AnExampleTestClass", "NaRknzcyrGrfgPynff for class")); } @Test public void verifyThatCustomColumnIsAddedToTheFailedTestsTableOnTheTestResultPage() throws Exception { - verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "failedtestresult", - "ROT13 for failed cases on test page", Pair.of("testCaseA", "grfgPnfrN for case")); + verifyThatTableContainsExpectedValues( + "/lastBuild/testReport/", + "failedtestresult", + "ROT13 for failed cases on test page", + Pair.of("testCaseA", "grfgPnfrN for case")); } @Test public void verifyThatCustomColumnIsAddedToTheClassesTableOnTheTestResultPage() throws Exception { - verifyThatTableContainsExpectedValues("/lastBuild/testReport/", "testresult", - "ROT13 for all packages on test page", Pair.of("io.jenkins.example", "vb.wraxvaf.rknzcyr for package")); + verifyThatTableContainsExpectedValues( + "/lastBuild/testReport/", + "testresult", + "ROT13 for all packages on test page", + Pair.of("io.jenkins.example", "vb.wraxvaf.rknzcyr for package")); } } diff --git a/src/test/java/hudson/tasks/junit/HistoryTest.java b/src/test/java/hudson/tasks/junit/HistoryTest.java index b395d90d..6177bde2 100644 --- a/src/test/java/hudson/tasks/junit/HistoryTest.java +++ b/src/test/java/hudson/tasks/junit/HistoryTest.java @@ -59,13 +59,14 @@ public void setUp() throws Exception { List projects = rule.jenkins.getAllItems(FreeStyleProject.class); Project theProject = null; for (Project p : projects) { - if (p.getName().equals(PROJECT_NAME)) theProject = p; + if (p.getName().equals(PROJECT_NAME)) { + theProject = p; + } } assertNotNull("We should have a project named " + PROJECT_NAME, theProject); project = (FreeStyleProject) theProject; } - @LocalData @Test public void testFailedSince() throws Exception { @@ -81,7 +82,7 @@ public void testFailedSince() throws Exception { rule.assertBuildStatus(Result.SUCCESS, build7); TestResult tr = build4.getAction(TestResultAction.class).getResult(); - assertEquals(2,tr.getFailedTests().size()); + assertEquals(2, tr.getFailedTests().size()); // In build 4, we expect these tests to have failed since these builds // org.jvnet.hudson.examples.small.deep.DeepTest.testScubaGear failed since 3 @@ -99,10 +100,10 @@ public void testFailedSince() throws Exception { int scubaFailedSince = scubaCase.getFailedSince(); assertEquals("scubaCase should have failed since build 3", 3, scubaFailedSince); - // In build 5 the scuba test begins to pass - TestResult tr5 = project.getBuildByNumber(5).getAction(TestResultAction.class).getResult(); - assertEquals(1,tr5.getFailedTests().size()); + TestResult tr5 = + project.getBuildByNumber(5).getAction(TestResultAction.class).getResult(); + assertEquals(1, tr5.getFailedTests().size()); deepPackage = tr5.byPackage("org.jvnet.hudson.examples.small.deep"); assertNotNull("deepPackage", deepPackage); assertTrue("package is passed", deepPackage.isPassed()); @@ -118,11 +119,12 @@ public void testFailedSince() throws Exception { ClassResult miscClass = smallPackage.getClassResult("MiscTest"); CaseResult eleanorCase = miscClass.getCaseResult("testEleanor"); assertTrue("eleanor failed", !eleanorCase.isPassed()); - assertEquals("eleanor has failed since build 3", 3, eleanorCase.getFailedSince()); + assertEquals("eleanor has failed since build 3", 3, eleanorCase.getFailedSince()); } @LocalData - @Test @Issue("SECURITY-2760") + @Test + @Issue("SECURITY-2760") public void testXSS() throws Exception { assertNotNull("project should exist", project); @@ -130,20 +132,25 @@ public void testXSS() throws Exception { TestResult tr = build4.getAction(TestResultAction.class).getResult(); tr.setDescription(""); - build4.save(); //Might be unnecessary + build4.save(); // Might be unnecessary try (final JenkinsRule.WebClient webClient = rule.createWebClient()) { Alerter alerter = new Alerter(); webClient.setJavaScriptEnabled(true); - webClient.getOptions().setThrowExceptionOnScriptError(false); //HtmlUnit finds a syntax error in bootstrap 5 - webClient.setAlertHandler(alerter); //This catches any alert dialog popup + webClient + .getOptions() + .setThrowExceptionOnScriptError(false); // HtmlUnit finds a syntax error in bootstrap 5 + webClient.setAlertHandler(alerter); // This catches any alert dialog popup final HtmlPage page = webClient.getPage(build4, "testReport/history/"); - assertNull(alerter.message); //No alert dialog popped up + assertNull(alerter.message); // No alert dialog popped up assertNull(alerter.page); final HtmlTable table = (HtmlTable) page.getElementById("testresult"); - final Optional descr = table.getRows().stream().flatMap(row -> row.getCells().stream()) - .filter(cell -> cell.getTextContent().equals("")) //cell.getTextContent() seems to translate back from > to < etc. + final Optional descr = table.getRows().stream() + .flatMap(row -> row.getCells().stream()) + .filter(cell -> cell.getTextContent() + .equals("")) // cell.getTextContent() seems to + // translate back from > to < etc. .findFirst(); assertTrue("Should have found the description", descr.isPresent()); } diff --git a/src/test/java/hudson/tasks/junit/JUnitParserTest.java b/src/test/java/hudson/tasks/junit/JUnitParserTest.java index 879a8d45..fb902281 100644 --- a/src/test/java/hudson/tasks/junit/JUnitParserTest.java +++ b/src/test/java/hudson/tasks/junit/JUnitParserTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -56,18 +56,19 @@ public class JUnitParserTest { @Rule public final JenkinsRule rule = new JenkinsRule(); + static hudson.tasks.junit.TestResult theResult = null; public static final class JUnitParserTestBuilder extends Builder implements Serializable { private static final long serialVersionUID = 1L; private String testResultLocation; + public JUnitParserTestBuilder(String testResultLocation) { this.testResultLocation = testResultLocation; } @Override - public boolean perform(AbstractBuild build, - Launcher launcher, BuildListener listener) + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { System.out.println("in perform..."); @@ -77,8 +78,8 @@ public boolean perform(AbstractBuild build, } System.out.println("...touched everything"); - hudson.tasks.junit.TestResult result = (new JUnitParser()).parseResult(testResultLocation, build, - null, build.getWorkspace(), launcher, listener); + hudson.tasks.junit.TestResult result = (new JUnitParser()) + .parseResult(testResultLocation, build, null, build.getWorkspace(), launcher, listener); System.out.println("back from parse"); assertNotNull("we should have a non-null result", result); @@ -89,9 +90,8 @@ public boolean perform(AbstractBuild build, } } - private FreeStyleProject project; - private String projectName = "junit_parser_test"; + private String projectName = "junit_parser_test"; @Before public void setUp() throws Exception { @@ -105,7 +105,7 @@ public void setUp() throws Exception { public void testJustParsing() throws Exception { FreeStyleBuild build = project.scheduleBuild2(0).get(100, TimeUnit.MINUTES); assertNotNull(build); - + // Now let's examine the result. We know lots of stuff about it because // we've analyzed the xml source files by hand. assertNotNull("we should have a result in the static member", theResult); @@ -113,37 +113,33 @@ public void testJustParsing() throws Exception { // Check the overall counts. We should have 1 failure, 0 skips, and 132 passes. Collection children = theResult.getChildren(); assertFalse("Should have several packages", children.isEmpty()); - assertTrue("Should have several pacakges", children.size() > 3); + assertTrue("Should have several pacakges", children.size() > 3); int passCount = theResult.getPassCount(); assertEquals("expecting many passes", 131, passCount); int failCount = theResult.getFailCount(); assertEquals("we should have one failure", 1, failCount); assertEquals("expected 0 skips", 0, theResult.getSkipCount()); - assertEquals("expected 132 total tests", 132, theResult.getTotalCount()); + assertEquals("expected 132 total tests", 132, theResult.getTotalCount()); - // Dig in to the failed test + // Dig in to the failed test final String EXPECTED_FAILING_TEST_NAME = "testDataCompatibilityWith1_282"; final String EXPECTED_FAILING_TEST_CLASSNAME = "hudson.security.HudsonPrivateSecurityRealmTest"; Collection failingTests = theResult.getFailedTests(); assertEquals("should have one failed test", 1, failingTests.size()); Map failedTestsByName = new HashMap<>(); - for (TestResult r: failingTests) { - failedTestsByName.put(r.getName(), r); + for (TestResult r : failingTests) { + failedTestsByName.put(r.getName(), r); } assertTrue("we've got the expected failed test", failedTestsByName.containsKey(EXPECTED_FAILING_TEST_NAME)); TestResult firstFailedTest = failedTestsByName.get(EXPECTED_FAILING_TEST_NAME); assertFalse("should not have passed this test", firstFailedTest.isPassed()); - + assertTrue(firstFailedTest instanceof CaseResult); - CaseResult firstFailedTestJunit = (CaseResult)firstFailedTest; + CaseResult firstFailedTestJunit = (CaseResult) firstFailedTest; assertEquals(EXPECTED_FAILING_TEST_CLASSNAME, firstFailedTestJunit.getClassName()); // TODO: Dig in to the passed tests, too - - } - - } diff --git a/src/test/java/hudson/tasks/junit/JUnitResultArchiverTest.java b/src/test/java/hudson/tasks/junit/JUnitResultArchiverTest.java index a522eb74..167f1b8a 100644 --- a/src/test/java/hudson/tasks/junit/JUnitResultArchiverTest.java +++ b/src/test/java/hudson/tasks/junit/JUnitResultArchiverTest.java @@ -92,18 +92,20 @@ public class JUnitResultArchiverTest { - @Rule public JenkinsRule j = new JenkinsRule(); + @Rule + public JenkinsRule j = new JenkinsRule(); @Rule public LoggerRule logRule = new LoggerRule().recordPackage(JUnitResultArchiver.class, Level.FINE); @ClassRule - public final static BuildWatcher buildWatcher = new BuildWatcher(); + public static final BuildWatcher buildWatcher = new BuildWatcher(); private FreeStyleProject project; private JUnitResultArchiver archiver; - @Before public void setUp() throws Exception { + @Before + public void setUp() throws Exception { project = j.createFreeStyleProject("junit"); archiver = new JUnitResultArchiver("*.xml"); project.getPublishersList().add(archiver); @@ -111,23 +113,27 @@ public class JUnitResultArchiverTest { } @LocalData("All") - @Test public void basic() throws Exception { - FreeStyleBuild build = - j.assertBuildStatus(Result.UNSTABLE, j.waitForCompletion(project.scheduleBuild2(0).waitForStart())); + @Test + public void basic() throws Exception { + FreeStyleBuild build = j.assertBuildStatus( + Result.UNSTABLE, j.waitForCompletion(project.scheduleBuild2(0).waitForStart())); assertTestResults(build); JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(j); wc.getPage(project); // project page wc.getPage(build); // build page - wc.getPage(build, "testReport"); // test report + wc.getPage(build, "testReport"); // test report wc.getPage(build, "testReport/hudson.security"); // package wc.getPage(build, "testReport/hudson.security/HudsonPrivateSecurityRealmTest/"); // class - wc.getPage(build, "testReport/hudson.security/HudsonPrivateSecurityRealmTest/testDataCompatibilityWith1_282/"); // method + wc.getPage( + build, + "testReport/hudson.security/HudsonPrivateSecurityRealmTest/testDataCompatibilityWith1_282/"); // method } - @LocalData("All") - @Test public void slave() throws Exception { + @LocalData("All") + @Test + public void slave() throws Exception { Assume.assumeFalse("TODO frequent TimeoutException from basic", Functions.isWindows()); DumbSlave node = j.createSlave("label1 label2", null); // the node needs to be online before showAgentLogs @@ -164,7 +170,8 @@ private void assertTestResults(FreeStyleBuild build) throws Exception { } @LocalData("All") - @Test public void persistence() throws Exception { + @Test + public void persistence() throws Exception { project.scheduleBuild2(0).get(60, TimeUnit.SECONDS); reloadJenkins(); @@ -180,10 +187,12 @@ private void reloadJenkins() throws Exception { } @LocalData("All") - @Test public void setDescription() throws Exception { + @Test + public void setDescription() throws Exception { FreeStyleBuild build = project.scheduleBuild2(0).get(10, TimeUnit.SECONDS); - CaseResult caseResult = build.getAction(TestResultAction.class).getFailedTests().get(0); + CaseResult caseResult = + build.getAction(TestResultAction.class).getFailedTests().get(0); String url = build.getUrl() + "/testReport/" + caseResult.getRelativePathFrom(caseResult.getTestResult()); testSetDescription(url, caseResult); @@ -195,7 +204,6 @@ private void reloadJenkins() throws Exception { PackageResult packageResult = classResult.getParent(); url = build.getUrl() + "/testReport/" + classResult.getParent().getSafeName(); testSetDescription(url, packageResult); - } private void testSetDescription(String url, TestObject object) throws Exception { @@ -213,7 +221,7 @@ private void testSetDescription(String url, TestObject object) throws Exception } private HtmlForm findForm(HtmlPage page, String action) { - for (HtmlForm form: page.getForms()) { + for (HtmlForm form : page.getForms()) { if (action.equals(form.getActionAttribute())) { return form; } @@ -222,12 +230,16 @@ private HtmlForm findForm(HtmlPage page, String action) { return null; } - @Test public void repeatedArchiving() throws Exception { + @Test + public void repeatedArchiving() throws Exception { doRepeatedArchiving(false); } - @Test public void repeatedArchivingSlave() throws Exception { + + @Test + public void repeatedArchivingSlave() throws Exception { doRepeatedArchiving(true); } + private void doRepeatedArchiving(boolean slave) throws Exception { if (slave) { DumbSlave s = j.createSlave("label1 label2", null); @@ -237,7 +249,8 @@ private void doRepeatedArchiving(boolean slave) throws Exception { project.getPublishersList().removeAll(JUnitResultArchiver.class); project.getBuildersList().add(new SimpleArchive("A", 7, 0)); project.getBuildersList().add(new SimpleArchive("B", 0, 1)); - FreeStyleBuild build = j.assertBuildStatus(Result.UNSTABLE, project.scheduleBuild2(0).get()); + FreeStyleBuild build = + j.assertBuildStatus(Result.UNSTABLE, project.scheduleBuild2(0).get()); List actions = build.getActions(TestResultAction.class); assertEquals(1, actions.size()); TestResultAction testResultAction = actions.get(0); @@ -247,46 +260,59 @@ private void doRepeatedArchiving(boolean slave) throws Exception { assertEquals("should have 1 failing test", 1, result.getFailCount()); assertEquals("should have 8 total tests", 8, testResultAction.getTotalCount()); assertEquals("should have 8 total tests", 8, result.getTotalCount()); - assertEquals(/* â…ž = 87.5% */87, testResultAction.getBuildHealth().getScore()); + assertEquals(/* â…ž = 87.5% */ 87, testResultAction.getBuildHealth().getScore()); } + public static final class SimpleArchive extends Builder { private final String name; private final int pass; private final int fail; + public SimpleArchive(String name, int pass, int fail) { this.name = name; this.pass = pass; this.fail = fail; } - @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { FilePath ws = build.getWorkspace(); try (OutputStream os = ws.child(name + ".xml").write()) { PrintWriter pw = new PrintWriter(os); - pw.println(""); + pw.println(""); for (int i = 0; i < pass; i++) { pw.println(""); } for (int i = 0; i < fail; i++) { - pw.println(""); + pw.println(""); } pw.println(""); pw.flush(); } - ws.touch(build.getTimeInMillis()+1); + ws.touch(build.getTimeInMillis() + 1); new JUnitResultArchiver(name + ".xml").perform(build, ws, launcher, listener); return true; } - @TestExtension public static final class DescriptorImpl extends BuildStepDescriptor { - @Override public boolean isApplicable(Class jobType) { + + @TestExtension + public static final class DescriptorImpl extends BuildStepDescriptor { + @Override + public boolean isApplicable(Class jobType) { return true; } - @Override public String getDisplayName() { + + @Override + public String getDisplayName() { return "Incremental JUnit result publishing"; } } } - @Test public void configRoundTrip() throws Exception { + @Test + public void configRoundTrip() throws Exception { JUnitResultArchiver a = new JUnitResultArchiver("TEST-*.xml"); a.setStdioRetention(StdioRetention.ALL.name()); a.setTestDataPublishers(Collections.singletonList(new MockTestDataPublisher("testing"))); @@ -303,25 +329,35 @@ public SimpleArchive(String name, int pass, int fail) { public static class MockTestDataPublisher extends TestDataPublisher { private final String name; - @DataBoundConstructor public MockTestDataPublisher(String name) { + + @DataBoundConstructor + public MockTestDataPublisher(String name) { this.name = name; } + public String getName() { return name; } - @Override public TestResultAction.Data contributeTestData(Run run, FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) throws IOException, InterruptedException { + + @Override + public TestResultAction.Data contributeTestData( + Run run, FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) + throws IOException, InterruptedException { return null; } // Needed to make this extension available to all tests for {@link #testDescribableRoundTrip()} - @TestExtension public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() { + @TestExtension + public static class DescriptorImpl extends Descriptor { + @Override + public String getDisplayName() { return "MockTestDataPublisher"; } } } - @Test public void noTestResultFilesAllowEmptyResult() throws Exception { + @Test + public void noTestResultFilesAllowEmptyResult() throws Exception { JUnitResultArchiver a = new JUnitResultArchiver("TEST-*.xml"); a.setAllowEmptyResults(true); FreeStyleProject freeStyleProject = j.createFreeStyleProject(); @@ -331,7 +367,8 @@ public String getName() { j.assertLogContains(Messages.JUnitResultArchiver_NoTestReportFound(), build); } - @Test public void noTestResultFilesDisallowEmptyResult() throws Exception { + @Test + public void noTestResultFilesDisallowEmptyResult() throws Exception { JUnitResultArchiver a = new JUnitResultArchiver("TEST-*.xml"); a.setAllowEmptyResults(false); FreeStyleProject freeStyleProject = j.createFreeStyleProject(); @@ -341,7 +378,8 @@ public String getName() { j.assertLogContains(Messages.JUnitResultArchiver_NoTestReportFound(), build); } - @Test public void noResultsInTestResultFilesAllowEmptyResult() throws Exception { + @Test + public void noResultsInTestResultFilesAllowEmptyResult() throws Exception { JUnitResultArchiver a = new JUnitResultArchiver("TEST-*.xml"); a.setAllowEmptyResults(true); FreeStyleProject freeStyleProject = j.createFreeStyleProject(); @@ -352,7 +390,8 @@ public String getName() { j.assertLogContains(Messages.JUnitResultArchiver_ResultIsEmpty(), build); } - @Test public void noResultsInTestResultFilesDisallowEmptyResult() throws Exception { + @Test + public void noResultsInTestResultFilesDisallowEmptyResult() throws Exception { JUnitResultArchiver a = new JUnitResultArchiver("TEST-*.xml"); a.setAllowEmptyResults(false); FreeStyleProject freeStyleProject = j.createFreeStyleProject(); @@ -365,7 +404,8 @@ public String getName() { public static final class NoResultsInTestResultFileBuilder extends Builder { @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { String fileName = "TEST-foo.xml"; String fileContent = ""; build.getWorkspace().child(fileName).write(fileContent, "UTF-8"); @@ -373,12 +413,16 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } } - @Test public void specialCharsInRelativePath() throws Exception { + @Test + public void specialCharsInRelativePath() throws Exception { Assume.assumeFalse(Functions.isWindows()); - final String ID_PREFIX = "test-../a=%3C%7C%23)/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/"; - final String EXPECTED = "org.twia.dao.DAOException: [S2001] Hibernate encountered an error updating Claim [null]"; + final String ID_PREFIX = + "test-../a=%3C%7C%23)/testReport/org.twia.vendor/VendorManagerTest/testCreateAdjustingFirm/"; + final String EXPECTED = + "org.twia.dao.DAOException: [S2001] Hibernate encountered an error updating Claim [null]"; - MatrixProject p = j.jenkins.createProject(MatrixProject.class, "test-" + j.jenkins.getItems().size()); + MatrixProject p = j.jenkins.createProject( + MatrixProject.class, "test-" + j.jenkins.getItems().size()); p.setAxes(new AxisList(new TextAxis("a", "<|#)"))); p.setScm(new SingleFileSCM("report.xml", getClass().getResource("junit-report-20090516.xml"))); p.getPublishersList().add(new JUnitResultArchiver("report.xml")); @@ -404,7 +448,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen @Test public void testDescribableRoundTrip() throws Exception { DescribableModel model = new DescribableModel<>(JUnitResultArchiver.class); - Map args = new TreeMap<>(); + Map args = new TreeMap<>(); args.put("testResults", "**/TEST-*.xml"); JUnitResultArchiver j = model.instantiate(args); @@ -416,18 +460,18 @@ public void testDescribableRoundTrip() throws Exception { assertEquals(args, model.uninstantiate(model.instantiate(args))); // Test roundtripping from a Pipeline-style describing of the publisher. - Map describedPublisher = new HashMap<>(); + Map describedPublisher = new HashMap<>(); describedPublisher.put("$class", "MockTestDataPublisher"); describedPublisher.put("name", "test"); args.put("testDataPublishers", Collections.singletonList(describedPublisher)); - Map described = model.uninstantiate(model.instantiate(args)); + Map described = model.uninstantiate(model.instantiate(args)); JUnitResultArchiver j2 = model.instantiate(described); List testDataPublishers = j2.getTestDataPublishers(); assertFalse(testDataPublishers.isEmpty()); assertEquals(1, testDataPublishers.size()); assertEquals(MockTestDataPublisher.class, testDataPublishers.get(0).getClass()); - assertEquals("test", ((MockTestDataPublisher)testDataPublishers.get(0)).getName()); + assertEquals("test", ((MockTestDataPublisher) testDataPublishers.get(0)).getName()); assertEquals(described, model.uninstantiate(model.instantiate(described))); } @@ -461,7 +505,8 @@ public void testXxe() throws Exception { // UNSTABLE // assertEquals(Result.SUCCESS, project.scheduleBuild2(0).get().getResult()); - YouCannotTriggerMe urlHandler = j.jenkins.getExtensionList(UnprotectedRootAction.class).get(YouCannotTriggerMe.class); + YouCannotTriggerMe urlHandler = + j.jenkins.getExtensionList(UnprotectedRootAction.class).get(YouCannotTriggerMe.class); assertEquals(0, urlHandler.triggerCount); } diff --git a/src/test/java/hudson/tasks/junit/SuiteResult2Test.java b/src/test/java/hudson/tasks/junit/SuiteResult2Test.java index 5634e704..2843b215 100644 --- a/src/test/java/hudson/tasks/junit/SuiteResult2Test.java +++ b/src/test/java/hudson/tasks/junit/SuiteResult2Test.java @@ -37,7 +37,8 @@ public class SuiteResult2Test { @SuppressFBWarnings({"DM_DEFAULT_ENCODING", "OS_OPEN_STREAM", "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE"}) - @Test public void sizeSurefire() throws Exception { + @Test + public void sizeSurefire() throws Exception { File data = File.createTempFile("TEST-", ".xml"); try { Writer w = new FileWriter(data); @@ -70,7 +71,8 @@ public class SuiteResult2Test { } finally { w.close(); } - File data2 = new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); + File data2 = + new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); try { w = new FileWriter(data2); try { @@ -86,7 +88,16 @@ public class SuiteResult2Test { w.close(); } SuiteResult sr = parseOne(data); - MemoryAssert.assertHeapUsage(sr, 1100 + /* Unicode overhead */2 * (int) (/*259946*/data.length() + /*495600*/data2.length() + /* SuiteResult.file */data.getAbsolutePath().length())); + MemoryAssert.assertHeapUsage( + sr, + 1100 + + /* Unicode overhead */ 2 + * (int) + ( + /*259946*/ data.length() + + /*495600*/ data2.length() + + /* SuiteResult.file */ data.getAbsolutePath() + .length())); // TODO serialize using TestResultAction.XSTREAM and verify that round-tripped object has same size } finally { data2.delete(); @@ -98,8 +109,7 @@ public class SuiteResult2Test { private SuiteResult parseOne(File file) throws Exception { List results = SuiteResult.parse(file, false, false, null); - assertEquals(1,results.size()); + assertEquals(1, results.size()); return results.get(0); } - } diff --git a/src/test/java/hudson/tasks/junit/SuiteResultTest.java b/src/test/java/hudson/tasks/junit/SuiteResultTest.java index ff3993a4..81de4ad5 100644 --- a/src/test/java/hudson/tasks/junit/SuiteResultTest.java +++ b/src/test/java/hudson/tasks/junit/SuiteResultTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt, Xavier Le Vourch, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -46,7 +46,7 @@ * Test cases for parsing JUnit report XML files. * As there are no XML schema for JUnit xml files, Hudson needs to handle * varied xml files. - * + * * @author Erik Ramfelt * @author Christoph Kutzinski */ @@ -65,13 +65,13 @@ private SuiteResult parseOne(File file) throws Exception { private SuiteResult parseOne(File file, StdioRetention stdioRetention) throws Exception { List results = SuiteResult.parse(file, stdioRetention, false, false, null); - assertEquals(1,results.size()); + assertEquals(1, results.size()); return results.get(0); } - + private SuiteResult parseOneWithProperties(File file) throws Exception { - List results = SuiteResult.parse(file, StdioRetention.DEFAULT, true, false,null); - assertEquals(1,results.size()); + List results = SuiteResult.parse(file, StdioRetention.DEFAULT, true, false, null); + assertEquals(1, results.size()); return results.get(0); } @@ -83,13 +83,28 @@ private List parseSuites(File file) throws Exception { @Test public void testIssue1233() throws Exception { SuiteResult result = parseOne(getDataFile("junit-report-1233.xml")); - + List cases = result.getCases(); - assertEquals("Class name is incorrect", "test.foo.bar.DefaultIntegrationTest", cases.get(0).getClassName()); - assertEquals("Class name is incorrect", "test.foo.bar.BundleResolverIntegrationTest", cases.get(1).getClassName()); - assertEquals("Class name is incorrect", "test.foo.bar.BundleResolverIntegrationTest", cases.get(2).getClassName()); - assertEquals("Class name is incorrect", "test.foo.bar.ProjectSettingsTest", cases.get(3).getClassName()); - assertEquals("Class name is incorrect", "test.foo.bar.ProjectSettingsTest", cases.get(4).getClassName()); + assertEquals( + "Class name is incorrect", + "test.foo.bar.DefaultIntegrationTest", + cases.get(0).getClassName()); + assertEquals( + "Class name is incorrect", + "test.foo.bar.BundleResolverIntegrationTest", + cases.get(1).getClassName()); + assertEquals( + "Class name is incorrect", + "test.foo.bar.BundleResolverIntegrationTest", + cases.get(2).getClassName()); + assertEquals( + "Class name is incorrect", + "test.foo.bar.ProjectSettingsTest", + cases.get(3).getClassName()); + assertEquals( + "Class name is incorrect", + "test.foo.bar.ProjectSettingsTest", + cases.get(4).getClassName()); } /** * JUnit report file is generated by SoapUI Pro 1.7.6 @@ -101,13 +116,31 @@ public void testIssue1463() throws Exception { List cases = result.getCases(); for (CaseResult caseResult : cases) { - assertEquals("Test class name is incorrect in " + caseResult.getName(), "WLI-FI-Tests-Fake", caseResult.getClassName()); + assertEquals( + "Test class name is incorrect in " + caseResult.getName(), + "WLI-FI-Tests-Fake", + caseResult.getClassName()); } - assertEquals("Test name is incorrect", "IF_importTradeConfirmationToDwh", cases.get(0).getName()); - assertEquals("Test name is incorrect", "IF_getAmartaDisbursements", cases.get(1).getName()); - assertEquals("Test name is incorrect", "IF_importGLReconDataToDwh", cases.get(2).getName()); - assertEquals("Test name is incorrect", "IF_importTradeInstructionsToDwh", cases.get(3).getName()); - assertEquals("Test name is incorrect", "IF_getDeviationTradeInstructions", cases.get(4).getName()); + assertEquals( + "Test name is incorrect", + "IF_importTradeConfirmationToDwh", + cases.get(0).getName()); + assertEquals( + "Test name is incorrect", + "IF_getAmartaDisbursements", + cases.get(1).getName()); + assertEquals( + "Test name is incorrect", + "IF_importGLReconDataToDwh", + cases.get(2).getName()); + assertEquals( + "Test name is incorrect", + "IF_importTradeInstructionsToDwh", + cases.get(3).getName()); + assertEquals( + "Test name is incorrect", + "IF_getDeviationTradeInstructions", + cases.get(4).getName()); assertEquals("Test name is incorrect", "IF_getDwhGLData", cases.get(5).getName()); } @@ -118,12 +151,12 @@ public void testIssue1463() throws Exception { @Test public void testIssue1472() throws Exception { List results = SuiteResult.parse(getDataFile("junit-report-1472.xml"), false, false, null); - assertTrue(results.size()>20); // lots of data here + assertTrue(results.size() > 20); // lots of data here SuiteResult sr0 = results.get(0); SuiteResult sr1 = results.get(1); - assertEquals("make_test.t_basic_lint_t",sr0.getName()); - assertEquals("make_test.t_basic_meta_t",sr1.getName()); + assertEquals("make_test.t_basic_lint_t", sr0.getName()); + assertEquals("make_test.t_basic_meta_t", sr1.getName()); assertTrue(!sr0.getStdout().equals(sr1.getStdout())); } @@ -141,9 +174,14 @@ public void testErrorDetails() throws Exception { List cases = result.getCases(); for (CaseResult caseResult : cases) { - assertEquals("Test class name is incorrect in " + caseResult.getName(), "some.package.somewhere.WhooHoo", caseResult.getClassName()); + assertEquals( + "Test class name is incorrect in " + caseResult.getName(), + "some.package.somewhere.WhooHoo", + caseResult.getClassName()); } - assertEquals("this normally has the string like, expected mullet, but got bream", cases.get(0).getErrorDetails()); + assertEquals( + "this normally has the string like, expected mullet, but got bream", + cases.get(0).getErrorDetails()); } @Test @@ -155,7 +193,7 @@ public void testSuiteResultPersistence() throws Exception { XmlFile xmlFile = new XmlFile(dest); xmlFile.write(source); - SuiteResult result = (SuiteResult)xmlFile.read(); + SuiteResult result = (SuiteResult) xmlFile.read(); assertNotNull(result); assertEquals(source.getName(), result.getName()); @@ -167,7 +205,7 @@ public void testSuiteResultPersistence() throws Exception { assertNotNull(result.getCase("test.foo.bar.BundleResolverIntegrationTest.testGetBundle")); } finally { dest.delete(); -} + } } @Issue("JENKINS-6516") @@ -331,7 +369,8 @@ public void testSuiteStdioTrimmingSurefire() throws Exception { } finally { w.close(); } - File data2 = new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); + File data2 = + new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); try { w = new FileWriter(data2); try { @@ -372,7 +411,8 @@ public void testSuiteStdioTrimmingSurefireOnFail() throws Exception { } finally { w.close(); } - File data2 = new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); + File data2 = + new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); try { w = new FileWriter(data2); try { @@ -414,7 +454,8 @@ public void testSuiteStdioTrimmingSurefireOnFailRetainAll() throws Exception { } finally { w.close(); } - File data2 = new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); + File data2 = + new File(data.getParentFile(), data.getName().replaceFirst("^TEST-(.+)[.]xml$", "$1-output.txt")); try { w = new FileWriter(data2); try { @@ -459,9 +500,9 @@ public void stdioNull() throws Exception { @Test public void testErrorInTestInitialization() throws Exception { SuiteResult suiteResult = parseOne(getDataFile("junit-report-6700.xml")); - + assertEquals(1, suiteResult.getCases().size()); - + CaseResult result = suiteResult.getCases().get(0); assertEquals(1, result.getFailCount()); assertTrue(result.getErrorStackTrace() != null); @@ -474,7 +515,7 @@ public void testParseNestedTestSuites() throws Exception { // 3 of them have actual some tests - each exactly one List results = parseSuites(getDataFile("junit-report-nested-testsuites.xml")); assertEquals(3, results.size()); - + for (SuiteResult result : results) { assertEquals(1, result.getCases().size()); } @@ -482,19 +523,19 @@ public void testParseNestedTestSuites() throws Exception { @Test public void testTestSuiteTimeAttribute() throws Exception { - // A report with blocks of testsuites some with and some without time attrs + // A report with blocks of testsuites some with and some without time attrs List results = parseSuites(getDataFile("junit-report-testsuite-time-attrs.xml")); - assertEquals(2503.1f, results.get(0).getDuration(), 2); //testsuit time - assertEquals(22.0f, results.get(1).getDuration(),2); //sum of test cases time - assertEquals(40.0f, results.get(2).getDuration(), 2); //testsuit time - assertEquals(20.0f, results.get(3).getDuration(), 2); //sum of test cases time + assertEquals(2503.1f, results.get(0).getDuration(), 2); // testsuit time + assertEquals(22.0f, results.get(1).getDuration(), 2); // sum of test cases time + assertEquals(40.0f, results.get(2).getDuration(), 2); // testsuit time + assertEquals(20.0f, results.get(3).getDuration(), 2); // sum of test cases time } @Test public void testTestParseTimeMethod() throws Exception { - // Tests parseTime() with various valid and invalid datetimes + // Tests parseTime() with various valid and invalid datetimes SuiteResult emptyResult = new SuiteResult("Test parseTime", "", "", null); - assertEquals(0, emptyResult.parseTime("1970-01-01T00:00:00.00")); + assertEquals(0, emptyResult.parseTime("1970-01-01T00:00:00.00")); assertEquals(1704280980000L, emptyResult.parseTime("2024-01-03T11:23:00.00")); assertEquals(1704284831000L, emptyResult.parseTime("2024-01-03T12:27:11")); assertEquals(1704285613000L, emptyResult.parseTime("2024-01-03T 12:40:13")); @@ -510,7 +551,7 @@ public void testTestParseTimeMethod() throws Exception { @Test public void testProperties() throws Exception { SuiteResult sr = parseOneWithProperties(getDataFile("junit-report-with-properties.xml")); - Map props = sr.getProperties(); + Map props = sr.getProperties(); assertEquals("value1", props.get("prop1")); String[] lines = props.get("multiline").split("\n"); assertEquals("", lines[0]); diff --git a/src/test/java/hudson/tasks/junit/TestNameTransformerTest.java b/src/test/java/hudson/tasks/junit/TestNameTransformerTest.java index bbeb982d..c101fc9c 100644 --- a/src/test/java/hudson/tasks/junit/TestNameTransformerTest.java +++ b/src/test/java/hudson/tasks/junit/TestNameTransformerTest.java @@ -12,7 +12,9 @@ public class TestNameTransformerTest { private static final String UNIQUE_NAME_FOR_TEST = "unique-name-to-test-name-transformer"; - @Rule public JenkinsRule j = new JenkinsRule(); + + @Rule + public JenkinsRule j = new JenkinsRule(); @TestExtension public static class TestTransformer extends TestNameTransformer { @@ -27,7 +29,8 @@ public String transformName(String name) { @Test public void testNameIsTransformed() throws Exception { - assertEquals(UNIQUE_NAME_FOR_TEST + "-transformed", TestNameTransformer.getTransformedName(UNIQUE_NAME_FOR_TEST)); + assertEquals( + UNIQUE_NAME_FOR_TEST + "-transformed", TestNameTransformer.getTransformedName(UNIQUE_NAME_FOR_TEST)); } @Issue("JENKINS-61787") @@ -35,11 +38,11 @@ public void testNameIsTransformed() throws Exception { public void testNameIsNotTransformedRemotely() throws Exception { assertEquals(UNIQUE_NAME_FOR_TEST, j.createOnlineSlave().getChannel().call(new Remote())); } + private static final class Remote extends MasterToSlaveCallable { @Override public String call() throws RuntimeException { return TestNameTransformer.getTransformedName(UNIQUE_NAME_FOR_TEST); } } - } diff --git a/src/test/java/hudson/tasks/junit/TestResultLinksTest.java b/src/test/java/hudson/tasks/junit/TestResultLinksTest.java index 9415f4b2..4571ddb1 100644 --- a/src/test/java/hudson/tasks/junit/TestResultLinksTest.java +++ b/src/test/java/hudson/tasks/junit/TestResultLinksTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -58,7 +58,6 @@ public class TestResultLinksTest { private FreeStyleProject project; private JUnitResultArchiver archiver; - @Before public void setUp() throws Exception { @@ -74,15 +73,16 @@ public void testFailureLinks() throws Exception { FreeStyleBuild build = project.scheduleBuild2(0).get(10, TimeUnit.SECONDS); rule.assertBuildStatus(Result.UNSTABLE, build); - TestResult theOverallTestResult = build.getAction(TestResultAction.class).getResult(); + TestResult theOverallTestResult = + build.getAction(TestResultAction.class).getResult(); CaseResult theFailedTestCase = theOverallTestResult.getFailedTests().get(0); String relativePath = theFailedTestCase.getRelativePathFrom(theOverallTestResult); - System.out.println("relative path seems to be: " + relativePath); + System.out.println("relative path seems to be: " + relativePath); JenkinsRule.WebClient wc = rule.createWebClient(); - String testReportPageUrl = project.getLastBuild().getUrl() + "/testReport"; - HtmlPage testReportPage = wc.goTo( testReportPageUrl ); + String testReportPageUrl = project.getLastBuild().getUrl() + "/testReport"; + HtmlPage testReportPage = wc.goTo(testReportPageUrl); Page packagePage = testReportPage.getAnchorByText("tacoshack.meals").click(); rule.assertGoodStatus(packagePage); // I expect this to work; just checking that my use of the APIs is correct. @@ -103,9 +103,11 @@ public void testFailureLinks() throws Exception { @LocalData @Test public void testNonDescendantRelativePath() throws Exception { - FreeStyleBuild build = project.scheduleBuild2(0).get(10, TimeUnit.MINUTES); // leave time for interactive debugging + FreeStyleBuild build = + project.scheduleBuild2(0).get(10, TimeUnit.MINUTES); // leave time for interactive debugging rule.assertBuildStatus(Result.UNSTABLE, build); - TestResult theOverallTestResult = build.getAction(TestResultAction.class).getResult(); + TestResult theOverallTestResult = + build.getAction(TestResultAction.class).getResult(); CaseResult theFailedTestCase = theOverallTestResult.getFailedTests().get(0); String relativePath = theFailedTestCase.getRelativePathFrom(theOverallTestResult); System.out.println("relative path seems to be: " + relativePath); @@ -119,9 +121,9 @@ public void testNonDescendantRelativePath() throws Exception { // If somehow we start being able to produce a root url, then I'll also tolerate a url that starts with that. boolean pathIsEmptyOrNull = relativePath2 == null || relativePath2.isEmpty(); boolean pathStartsWithRootUrl = !pathIsEmptyOrNull && relativePath2.startsWith(rule.jenkins.getRootUrl()); - assertTrue("relative path is empty OR begins with the app root", pathIsEmptyOrNull || pathStartsWithRootUrl ); + assertTrue("relative path is empty OR begins with the app root", pathIsEmptyOrNull || pathStartsWithRootUrl); } - + @Issue("JENKINS-31660") @Test public void testPreviousBuildNotLoaded() throws IOException, URISyntaxException { @@ -136,7 +138,7 @@ public FreeStyleBuild getPreviousBuild() { } }; testResult.freeze(new TestResultAction(build, testResult, null)); - } + } @Test public void testFailedSinceAfterSkip() throws IOException, URISyntaxException { diff --git a/src/test/java/hudson/tasks/junit/TestResultPublishingTest.java b/src/test/java/hudson/tasks/junit/TestResultPublishingTest.java index c5bb6593..a59ac4a7 100644 --- a/src/test/java/hudson/tasks/junit/TestResultPublishingTest.java +++ b/src/test/java/hudson/tasks/junit/TestResultPublishingTest.java @@ -68,14 +68,13 @@ public class TestResultPublishingTest { public final JenkinsRule rule = new JenkinsRule(); @ClassRule - public final static BuildWatcher buildWatcher = new BuildWatcher(); + public static final BuildWatcher buildWatcher = new BuildWatcher(); private FreeStyleProject project; private JUnitResultArchiver archiver; private final String BASIC_TEST_PROJECT = "percival"; private final String TEST_PROJECT_WITH_HISTORY = "wonky"; - @Before public void setUp() throws Exception { project = rule.createFreeStyleProject(BASIC_TEST_PROJECT); @@ -93,13 +92,14 @@ public void testBasic() throws Exception { assertTestResults(build); JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(rule); - wc.getPage(build, "testReport"); // test report + wc.getPage(build, "testReport"); // test report wc.getPage(build, "testReport/hudson.security"); // package wc.getPage(build, "testReport/hudson.security/HudsonPrivateSecurityRealmTest/"); // class - wc.getPage(build, "testReport/hudson.security/HudsonPrivateSecurityRealmTest/testDataCompatibilityWith1_282/"); // method + wc.getPage( + build, + "testReport/hudson.security/HudsonPrivateSecurityRealmTest/testDataCompatibilityWith1_282/"); // method } - @LocalData @Test public void testSlave() throws Exception { @@ -115,7 +115,6 @@ public void testSlave() throws Exception { testBasic(); } - /** * Verify that we can successfully parse and display test results in the * open junit test result publishing toolchain. Ensure that we meet this @@ -127,7 +126,7 @@ public void testSlave() throws Exception { @LocalData @Test public void testOpenJUnitPublishing() throws IOException, SAXException { - Project proj = (Project)rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); + Project proj = (Project) rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); assertNotNull("We should have a project named " + TEST_PROJECT_WITH_HISTORY, proj); // Validate that there are test results where I expect them to be: @@ -143,10 +142,14 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { // after "Latest Test Result" it should say "no failures" rule.assertXPathResultsContainText(projectPage, "//td", "(no failures)"); // there should be a test result trend graph - HtmlElement trendGraphCaption = (HtmlElement) projectPage.getByXPath( "//div[@class='test-trend-caption']").get(0); + HtmlElement trendGraphCaption = (HtmlElement) + projectPage.getByXPath("//div[@class='test-trend-caption']").get(0); assertThat(trendGraphCaption.getTextContent(), is("Test Result Trend")); - HtmlElement testCanvas = (HtmlElement) trendGraphCaption.getNextSibling().getFirstChild(); - assertTrue("couldn't find test result trend graph", testCanvas.getAttribute("class").contains("echarts-trend")); + HtmlElement testCanvas = + (HtmlElement) trendGraphCaption.getNextSibling().getFirstChild(); + assertTrue( + "couldn't find test result trend graph", + testCanvas.getAttribute("class").contains("echarts-trend")); XmlPage xmlProjectPage = wc.goToXml(proj.getUrl() + "/lastBuild/testReport/api/xml"); rule.assertXPath(xmlProjectPage, "/testResult"); @@ -155,7 +158,11 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { rule.assertXPathValue(xmlProjectPage, "/testResult/failCount", "0"); rule.assertXPathValue(xmlProjectPage, "/testResult/passCount", "4"); rule.assertXPathValue(xmlProjectPage, "/testResult/skipCount", "0"); - String[] packages = {"org.jvnet.hudson.examples.small.AppTest", "org.jvnet.hudson.examples.small.MiscTest", "org.jvnet.hudson.examples.small.deep.DeepTest"}; + String[] packages = { + "org.jvnet.hudson.examples.small.AppTest", + "org.jvnet.hudson.examples.small.MiscTest", + "org.jvnet.hudson.examples.small.deep.DeepTest" + }; for (String packageName : packages) { rule.assertXPath(xmlProjectPage, "/testResult/suite/case/className[text()='" + packageName + "']"); } @@ -164,7 +171,8 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { HtmlPage buildPage = wc.getPage(proj.getBuildByNumber(3)); rule.assertGoodStatus(buildPage); // We expect to see one failure, for com.yahoo.breakable.misc.UglyTest.becomeUglier - // which should link to http://localhost:8080/job/wonky/3/testReport/org.jvnet.hudson.examples.small/MiscTest/testEleanor/ + // which should link to + // http://localhost:8080/job/wonky/3/testReport/org.jvnet.hudson.examples.small/MiscTest/testEleanor/ rule.assertXPathResultsContainText(buildPage, "//a", "org.jvnet.hudson.examples.small.MiscTest.testEleanor"); HtmlAnchor failingTestLink = buildPage.getAnchorByText("org.jvnet.hudson.examples.small.MiscTest.testEleanor"); assertNotNull(failingTestLink); @@ -185,15 +193,18 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { rule.assertXPathValue(xmlTestReportPage, "/testResult/skipCount", "0"); // Make sure the right tests passed and failed - rule.assertXPathValue(xmlTestReportPage, "/testResult/suite/case[className/text()='org.jvnet.hudson.examples.small.AppTest']/status", "PASSED"); + rule.assertXPathValue( + xmlTestReportPage, + "/testResult/suite/case[className/text()='org.jvnet.hudson.examples.small.AppTest']/status", + "PASSED"); rule.assertXPathValue(xmlTestReportPage, "/testResult/suite/case[name/text()='testEleanor']/status", "FAILED"); - // TODO: implement more of these tests // On the lastBuild/testReport page: // Breadcrumbs should read #6 > Test Result where Test Result is a link to this page // inside of div id="main-panel" we should find the text "0 failures (-1)" - // we should have a blue bar which is blue all the way across: div style="width: 100%; height: 1em; background-color: rgb(114, 159, 207); + // we should have a blue bar which is blue all the way across: div style="width: 100%; height: 1em; + // background-color: rgb(114, 159, 207); // we should find the words "7 tests (?0)" // we should find the words "All Tests" // we should find a table @@ -202,17 +213,33 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { // org.jvnet.hudson.examples.small 0ms 0 -1 0 3 // org.jvnet.hudson.examples.small.deep 4ms 0 0 0 1 Run theRun = proj.getBuildByNumber(7); - assertTestResultsAsExpected(wc, theRun, "/testReport", - "org.jvnet.hudson.examples.small", "0 ms", "SUCCESS", - /* total tests expected, diff */ 3, 0, - /* fail count expected, diff */ 0, -1, - /* skip count expected, diff */ 0, 0); - - assertTestResultsAsExpected(wc, theRun, "/testReport", - "org.jvnet.hudson.examples.small.deep", "4 ms", "SUCCESS", - /* total tests expected, diff */ 1, 0, - /* fail count expected, diff */ 0, 0, - /* skip count expected, diff */ 0, 0); + assertTestResultsAsExpected( + wc, + theRun, + "/testReport", + "org.jvnet.hudson.examples.small", + "0 ms", + "SUCCESS", + /* total tests expected, diff */ 3, + 0, + /* fail count expected, diff */ 0, + -1, + /* skip count expected, diff */ 0, + 0); + + assertTestResultsAsExpected( + wc, + theRun, + "/testReport", + "org.jvnet.hudson.examples.small.deep", + "4 ms", + "SUCCESS", + /* total tests expected, diff */ 1, + 0, + /* fail count expected, diff */ 0, + 0, + /* skip count expected, diff */ 0, + 0); // TODO: more, more, more. // TODO: test report history by package @@ -226,19 +253,25 @@ public void testOpenJUnitPublishing() throws IOException, SAXException { @LocalData @Test public void testInterBuildDiffs() throws IOException, SAXException { - Project proj = (Project)rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); + Project proj = (Project) rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); assertNotNull("We should have a project named " + TEST_PROJECT_WITH_HISTORY, proj); // Validate that there are test results where I expect them to be: JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(rule); Run theRun = proj.getBuildByNumber(4); - assertTestResultsAsExpected(wc, theRun, "/testReport", - "org.jvnet.hudson.examples.small", "12 ms", "FAILURE", - /* total tests expected, diff */ 3, 0, - /* fail count expected, diff */ 1, 0, - /* skip count expected, diff */ 0, 0); - - + assertTestResultsAsExpected( + wc, + theRun, + "/testReport", + "org.jvnet.hudson.examples.small", + "12 ms", + "FAILURE", + /* total tests expected, diff */ 3, + 0, + /* fail count expected, diff */ 1, + 0, + /* skip count expected, diff */ 0, + 0); } /** @@ -249,15 +282,16 @@ public void testInterBuildDiffs() throws IOException, SAXException { @LocalData @Test public void testHistoryPageOpenJunit() throws IOException, SAXException { - Project proj = (Project)rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); + Project proj = (Project) rule.jenkins.getItem(TEST_PROJECT_WITH_HISTORY); assertNotNull("We should have a project named " + TEST_PROJECT_WITH_HISTORY, proj); // Validate that there are test results where I expect them to be: JenkinsRule.WebClient wc = WebClientFactory.createWebClientWithDisabledJavaScript(rule); - HtmlPage historyPage = wc.getPage(proj.getBuildByNumber(7),"/testReport/history/"); + HtmlPage historyPage = wc.getPage(proj.getBuildByNumber(7), "/testReport/history/"); rule.assertGoodStatus(historyPage); - HtmlElement historyCard = (HtmlElement) historyPage.getByXPath( "//div[@class='card ']").get(0); + HtmlElement historyCard = + (HtmlElement) historyPage.getByXPath("//div[@class='card ']").get(0); assertThat(historyCard.getTextContent(), containsString("History")); DomElement wholeTable = historyPage.getElementById("testresult"); assertNotNull("table with id 'testresult' exists", wholeTable); @@ -273,12 +307,9 @@ public void testHistoryPageOpenJunit() throws IOException, SAXException { // of detecting whether the history results are present. String tableText = table.getTextContent(); - assertTrue("Table text is missing the project name", - tableText.contains(TEST_PROJECT_WITH_HISTORY)); - assertTrue("Table text is missing the build number", - tableText.contains("7")); - assertTrue("Table text is missing the test duration", - tableText.contains("4 ms")); + assertTrue("Table text is missing the project name", tableText.contains(TEST_PROJECT_WITH_HISTORY)); + assertTrue("Table text is missing the build number", tableText.contains("7")); + assertTrue("Table text is missing the test duration", tableText.contains("4 ms")); } @Issue("JENKINS-19186") @@ -290,40 +321,51 @@ public void testBrokenResultFile() throws Exception { p.getPublishersList().add(new JUnitResultArchiver("TEST-foo.xml", false, null)); rule.assertBuildStatus(Result.UNSTABLE, p.scheduleBuild2(0).get()); } + private static final class TestBuilder extends Builder { - @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { build.getWorkspace().child("TEST-foo.xml").write("", null); return true; } } void assertStringEmptyOrNull(String msg, String str) { - if (str==null) + if (str == null) { return; - if (str.equals("")) + } + if (str.equals("")) { return; + } fail(msg + "(should be empty or null) : '" + str + "'"); } void assertPaneDiffText(String msg, int expectedValue, Object paneObj) { - assertTrue( "paneObj should be an HtmlElement, it was " + paneObj.getClass(), paneObj instanceof HtmlElement ); + assertTrue("paneObj should be an HtmlElement, it was " + paneObj.getClass(), paneObj instanceof HtmlElement); String paneText = ((HtmlElement) paneObj).asNormalizedText(); - if (expectedValue==0) { + if (expectedValue == 0) { assertStringEmptyOrNull(msg, paneText); } else { - String expectedString = - (expectedValue >= 1 ? "+" : "-") - + Math.abs(expectedValue); + String expectedString = (expectedValue >= 1 ? "+" : "-") + Math.abs(expectedValue); assertEquals(msg, expectedString, paneText); } } - void assertTestResultsAsExpected(JenkinsRule.WebClient wc, Run run, String restOfUrl, - String packageName, - String expectedResult, String expectedDurationStr, - int expectedTotalTests, int expectedTotalDiff, - int expectedFailCount, int expectedFailDiff, - int expectedSkipCount, int expectedSkipDiff) throws IOException, SAXException { + void assertTestResultsAsExpected( + JenkinsRule.WebClient wc, + Run run, + String restOfUrl, + String packageName, + String expectedResult, + String expectedDurationStr, + int expectedTotalTests, + int expectedTotalDiff, + int expectedFailCount, + int expectedFailDiff, + int expectedSkipCount, + int expectedSkipDiff) + throws IOException, SAXException { // TODO: verify expectedResult // TODO: verify expectedDuration @@ -337,11 +379,11 @@ void assertTestResultsAsExpected(JenkinsRule.WebClient wc, Run run, String restO rule.assertXPathValue(xmlPage, "/packageResult/name", packageName); // TODO: verify html results - HtmlPage testResultPage = wc.getPage(run, restOfUrl); + HtmlPage testResultPage = wc.getPage(run, restOfUrl); // Verify inter-build diffs in html table - String xpathToFailDiff = "//table[@id='testresult']//tr[td//span[text()=\"" + packageName + "\"]]/td[4]"; - String xpathToSkipDiff = "//table[@id='testresult']//tr[td//span[text()=\"" + packageName + "\"]]/td[6]"; + String xpathToFailDiff = "//table[@id='testresult']//tr[td//span[text()=\"" + packageName + "\"]]/td[4]"; + String xpathToSkipDiff = "//table[@id='testresult']//tr[td//span[text()=\"" + packageName + "\"]]/td[6]"; String xpathToTotalDiff = "//table[@id='testresult']//tr[td//span[text()=\"" + packageName + "\"]]/td[last()]"; Object totalDiffObj = testResultPage.getFirstByXPath(xpathToTotalDiff); @@ -353,7 +395,8 @@ void assertTestResultsAsExpected(JenkinsRule.WebClient wc, Run run, String restO Object skipDiffObj = testResultPage.getFirstByXPath(xpathToSkipDiff); assertPaneDiffText("skip diff", expectedSkipDiff, skipDiffObj); - // TODO: The link in the table for each of the three packages in the testReport table should link to a by-package page, + // TODO: The link in the table for each of the three packages in the testReport table should link to a + // by-package page, // TODO: for example, http://localhost:8080/job/breakable/lastBuild/testReport/com.yahoo.breakable.misc/ } @@ -362,7 +405,6 @@ void assertTestResultsAsExpected(JenkinsRule.WebClient wc, Run run, String restO // TODO: From users' point of view, Open Source *Unit publishers should continue to work as if nothing has changed // TODO: * Old testReport URLs should still work - private void assertTestResults(FreeStyleBuild build) { TestResultAction testResultAction = build.getAction(TestResultAction.class); assertNotNull("no TestResultAction", testResultAction); @@ -376,5 +418,4 @@ private void assertTestResults(FreeStyleBuild build) { assertEquals("should have 132 total tests", 132, testResultAction.getTotalCount()); assertEquals("should have 132 total tests", 132, result.getTotalCount()); } - } diff --git a/src/test/java/hudson/tasks/junit/TestResultTest.java b/src/test/java/hudson/tasks/junit/TestResultTest.java index 4ef924f6..d688ea6a 100644 --- a/src/test/java/hudson/tasks/junit/TestResultTest.java +++ b/src/test/java/hudson/tasks/junit/TestResultTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -79,13 +79,13 @@ public void testIpsTests() throws Exception { /** * This test verifies compatibility of JUnit test results persisted to * XML prior to the test code refactoring. - * + * * @throws Exception */ @Test public void testXmlCompatibility() throws Exception { XmlFile xmlFile = new XmlFile(TestResultAction.XSTREAM, getDataFile("junitResult.xml")); - TestResult result = (TestResult)xmlFile.read(); + TestResult result = (TestResult) xmlFile.read(); // Regenerate the transient data result.tally(); @@ -120,7 +120,9 @@ public void testSkippedMessageIsAddedWhenTheMessageAttributeIsNull() throws IOEx testResult.parse(getDataFile("SKIPPED_MESSAGE/skippedTestResult.xml"), null); List suiteResults = new ArrayList<>(testResult.getSuites()); CaseResult caseResult = suiteResults.get(0).getCases().get(0); - assertEquals("Given skip This Test........................................................pending\n", caseResult.getSkippedMessage()); + assertEquals( + "Given skip This Test........................................................pending\n", + caseResult.getSkippedMessage()); } /** @@ -135,11 +137,11 @@ public void testDuplicateTestMethods() throws IOException, URISyntaxException { testResult.parse(getDataFile("JENKINS-13214/27540.xml"), null); testResult.parse(getDataFile("JENKINS-13214/29734.xml"), null); testResult.tally(); - + assertEquals("Wrong number of test suites", 1, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 3, testResult.getTotalCount()); } - + @Issue("JENKINS-12457") @Test public void testTestSuiteDistributedOverMultipleFilesIsCountedAsOne() throws IOException, URISyntaxException { @@ -147,11 +149,11 @@ public void testTestSuiteDistributedOverMultipleFilesIsCountedAsOne() throws IOE testResult.parse(getDataFile("JENKINS-12457/TestSuite_a1.xml"), null); testResult.parse(getDataFile("JENKINS-12457/TestSuite_a2.xml"), null); testResult.tally(); - + assertEquals("Wrong number of testsuites", 1, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 2, testResult.getTotalCount()); - - // check duration: 157.980 (TestSuite_a1.xml) and 15.000 (TestSuite_a2.xml) = 172.98 + + // check duration: 157.980 (TestSuite_a1.xml) and 15.000 (TestSuite_a2.xml) = 172.98 assertEquals("Wrong duration for test result", 172.98, testResult.getDuration(), 0.1); } @@ -216,19 +218,22 @@ public void testSuiteWithMultipleClasses() throws IOException, URISyntaxExceptio // This looks like a bug in the JUnit runner used by Android tests. assertEquals("Wrong duration for test result", 2.0, testResult.getDuration(), 0.1); - SuiteResult suite = testResult.getSuite("org.catrobat.paintroid.test.integration.ActivityOpenedFromPocketCodeNewImageTest"); + SuiteResult suite = + testResult.getSuite("org.catrobat.paintroid.test.integration.ActivityOpenedFromPocketCodeNewImageTest"); assertNotNull(suite); assertEquals("Wrong number of test classes", 2, suite.getClassNames().size()); - CaseResult case1 = suite.getCase("org.catrobat.paintroid.test.integration.BitmapIntegrationTest.testDrawingSurfaceBitmapIsScreenSize"); + CaseResult case1 = suite.getCase( + "org.catrobat.paintroid.test.integration.BitmapIntegrationTest.testDrawingSurfaceBitmapIsScreenSize"); assertNotNull(case1); ClassResult class1 = case1.getParent(); assertNotNull(class1); assertEquals("org.catrobat.paintroid.test.integration.BitmapIntegrationTest", class1.getFullName()); - assertEquals("Wrong duration for test class", 5.0, class1.getDuration(),0.1); + assertEquals("Wrong duration for test class", 5.0, class1.getDuration(), 0.1); - CaseResult case2 = suite.getCase("org.catrobat.paintroid.test.integration.LandscapeTest.testColorPickerDialogSwitchTabsInLandscape"); + CaseResult case2 = suite.getCase( + "org.catrobat.paintroid.test.integration.LandscapeTest.testColorPickerDialogSwitchTabsInLandscape"); assertNotNull(case2); ClassResult class2 = case2.getParent(); assertNotNull(class2); @@ -245,11 +250,11 @@ public void testMergeOriginalAntOutput() throws IOException, URISyntaxException testResult.parse(getDataFile("JENKINS-48583/TESTS-TestSuites.xml"), null); testResult.parse(getDataFile("JENKINS-48583/TEST-com.sample.test.TestMessage.xml"), null); testResult.tally(); - + assertEquals("Wrong number of testsuites", 2, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 7, testResult.getTotalCount()); } - + /** * Sometimes legitimage test cases are split over multiple files with identical timestamps. */ @@ -265,7 +270,7 @@ public void testNonDuplicatedTestSuiteIsCounted() throws IOException, URISyntaxE assertEquals("Wrong number of testsuites", 1, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 3, testResult.getTotalCount()); } - + @Issue("JENKINS-63113") @Test public void testTestcaseWithEmptyName() throws Exception { @@ -296,15 +301,15 @@ public void skipOldReports() throws Exception { Files.setLastModifiedTime(testResultFile2.toPath(), FileTime.fromMillis(start - 4000)); DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(new File("src/test/resources/hudson/tasks/junit/old-reports/")); - directoryScanner.setIncludes(new String[]{"*.xml"}); + directoryScanner.setIncludes(new String[] {"*.xml"}); directoryScanner.scan(); - assertEquals( "directory scanner must find 2 files", 2, directoryScanner.getIncludedFiles().length); - TestResult testResult = new TestResult(start, directoryScanner, true, false, false, new PipelineTestDetails(),true); + assertEquals("directory scanner must find 2 files", 2, directoryScanner.getIncludedFiles().length); + TestResult testResult = + new TestResult(start, directoryScanner, true, false, false, new PipelineTestDetails(), true); testResult.tally(); assertEquals("Wrong number of testsuites", 2, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 3, testResult.getTotalCount()); - } @Test @@ -316,43 +321,44 @@ public void parseOldReports() throws Exception { Files.setLastModifiedTime(testResultFile2.toPath(), FileTime.fromMillis(start - 4000)); DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(new File("src/test/resources/hudson/tasks/junit/old-reports/")); - directoryScanner.setIncludes(new String[]{"*.xml"}); + directoryScanner.setIncludes(new String[] {"*.xml"}); directoryScanner.scan(); - assertEquals( "directory scanner must find 2 files", 2, directoryScanner.getIncludedFiles().length); - TestResult testResult = new TestResult(start, directoryScanner, true, false, new PipelineTestDetails(),false); + assertEquals("directory scanner must find 2 files", 2, directoryScanner.getIncludedFiles().length); + TestResult testResult = new TestResult(start, directoryScanner, true, false, new PipelineTestDetails(), false); testResult.tally(); assertEquals("Wrong number of testsuites", 4, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 6, testResult.getTotalCount()); - } + @Test public void clampDuration() throws Exception { long start = System.currentTimeMillis(); File testResultFile1 = new File("src/test/resources/hudson/tasks/junit/junit-report-bad-duration.xml"); DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(new File("src/test/resources/hudson/tasks/junit/")); - directoryScanner.setIncludes(new String[]{"*-bad-duration.xml"}); + directoryScanner.setIncludes(new String[] {"*-bad-duration.xml"}); directoryScanner.scan(); - assertEquals( "directory scanner must find 1 files", 1, directoryScanner.getIncludedFiles().length); + assertEquals("directory scanner must find 1 files", 1, directoryScanner.getIncludedFiles().length); TestResult testResult = new TestResult(start, directoryScanner, true, false, new PipelineTestDetails(), false); testResult.tally(); assertEquals("Negative duration is invalid", 100, testResult.getDuration(), 0.00001); assertEquals("Wrong number of testsuites", 1, testResult.getSuites().size()); assertEquals("Wrong number of test cases", 2, testResult.getTotalCount()); } + @Test public void testStartTimes() throws Exception { - // Tests that start times are as expected for file with a mix of valid, - // invalid, and unspecified timestamps. + // Tests that start times are as expected for file with a mix of valid, + // invalid, and unspecified timestamps. TestResult testResult = new TestResult(); testResult.parse(getDataFile("junit-report-testsuite-various-timestamps.xml")); testResult.tally(); // Test that TestResult startTime is the startTime of the earliest suite. assertEquals(1704281235000L, testResult.getStartTime()); - + // Test that suites have correct start times - List suites = (List)testResult.getSuites(); + List suites = (List) testResult.getSuites(); assertEquals(-1, suites.get(0).getStartTime()); assertEquals(1704284831000L, suites.get(1).getStartTime()); assertEquals(1704285613000L, suites.get(2).getStartTime()); @@ -361,26 +367,26 @@ public void testStartTimes() throws Exception { assertEquals(-1, suites.get(5).getStartTime()); assertEquals(1704288431210L, suites.get(6).getStartTime()); assertEquals(1704281235000L, suites.get(7).getStartTime()); - + // Test each package and its descendants for correct start times. - PackageResult pkg = testResult.byPackage("(root)"); + PackageResult pkg = testResult.byPackage("(root)"); assertEquals(1704281235000L, pkg.getStartTime()); - + ClassResult class1 = pkg.getClassResult("contents adjust properly when resizing test"); CaseResult case1 = class1.getCaseResult("testResize"); assertEquals(1704288431210L, class1.getStartTime()); assertEquals(1704288431210L, case1.getStartTime()); - + ClassResult class2 = pkg.getClassResult("date reflects offset test"); CaseResult case2 = class2.getCaseResult("testDate"); assertEquals(-1, class2.getStartTime()); assertEquals(-1, case2.getStartTime()); - + ClassResult class3 = pkg.getClassResult("get test"); CaseResult case3 = class3.getCaseResult("testGet"); assertEquals(-1, class3.getStartTime()); assertEquals(-1, case3.getStartTime()); - + ClassResult class4 = pkg.getClassResult("testButtons"); CaseResult case4 = class4.getCaseResult("home_button_redirects_to_home_test"); CaseResult case5 = class4.getCaseResult("sign_out_button_ends_session_test"); @@ -389,34 +395,33 @@ public void testStartTimes() throws Exception { assertEquals(1704285613000L, case4.getStartTime()); assertEquals(1704285617000L, case5.getStartTime()); assertEquals(1704285628000L, case6.getStartTime()); - + ClassResult class5 = pkg.getClassResult("testPassword"); CaseResult case7 = class5.getCaseResult("invalid_if_password_does_not_match_test"); CaseResult case8 = class5.getCaseResult("invalid_if_password_is_weak_test"); assertEquals(1704284831000L, class5.getStartTime()); assertEquals(1704284831000L, case7.getStartTime()); assertEquals(1704284838000L, case8.getStartTime()); - + ClassResult class6 = pkg.getClassResult("pages load in under ten seconds under ideal conditions test"); CaseResult case9 = class6.getCaseResult("testExperience"); assertEquals(1704284864000L, class6.getStartTime()); assertEquals(1704284864000L, case9.getStartTime()); - + ClassResult class7 = pkg.getClassResult("popups triggered when hovering test"); CaseResult case10 = class7.getCaseResult("testPopup"); assertEquals(-1, class7.getStartTime()); assertEquals(-1, case10.getStartTime()); - + ClassResult class8 = pkg.getClassResult("proper images displayed when items added"); CaseResult case11 = class8.getCaseResult("testShop"); assertEquals(1704281235000L, class8.getStartTime()); assertEquals(1704281235000L, case11.getStartTime()); - + ClassResult class9 = pkg.getClassResult("time offset is correct test"); CaseResult case12 = class9.getCaseResult("testOffset"); assertEquals(-1, class9.getStartTime()); assertEquals(-1, case12.getStartTime()); - } /* @@ -425,7 +430,8 @@ public void testStartTimes() throws Exception { */ @Test public void bigResultReadWrite() throws Exception { - List results = SuiteResult.parse(getDataFile("junit-report-huge.xml"), StdioRetention.ALL, true, true, null); + List results = + SuiteResult.parse(getDataFile("junit-report-huge.xml"), StdioRetention.ALL, true, true, null); assertEquals(1, results.size()); SuiteResult sr = results.get(0); @@ -439,11 +445,12 @@ public void bigResultReadWrite() throws Exception { XmlFile f2 = new XmlFile(TestResultAction.XSTREAM, tmp.newFile("junitResult2.xml")); f2.write(tr2); - assertEquals(2, tr.getSuites().stream().findFirst().get().getProperties().size()); - assertEquals(2, tr2.getSuites().stream().findFirst().get().getProperties().size()); + assertEquals( + 2, tr.getSuites().stream().findFirst().get().getProperties().size()); + assertEquals( + 2, tr2.getSuites().stream().findFirst().get().getProperties().size()); boolean isTwoEqual = FileUtils.contentEquals(f.getFile(), f2.getFile()); assertTrue("Forgot to implement XML parsing for something?", isTwoEqual); } - } diff --git a/src/test/java/hudson/tasks/junit/pipeline/JUnitResultsStepTest.java b/src/test/java/hudson/tasks/junit/pipeline/JUnitResultsStepTest.java index 0d4c0af1..3163e108 100644 --- a/src/test/java/hudson/tasks/junit/pipeline/JUnitResultsStepTest.java +++ b/src/test/java/hudson/tasks/junit/pipeline/JUnitResultsStepTest.java @@ -59,7 +59,7 @@ public class JUnitResultsStepTest { public final JenkinsRule rule = new JenkinsRule(); @ClassRule - public final static BuildWatcher buildWatcher = new BuildWatcher(); + public static final BuildWatcher buildWatcher = new BuildWatcher(); @Test public void configRoundTrip() throws Exception { @@ -69,26 +69,31 @@ public void configRoundTrip() throws Exception { step.setAllowEmptyResults(true); st.assertRoundTrip(step, "junit allowEmptyResults: true, testResults: '**/target/surefire-reports/TEST-*.xml'"); step.setHealthScaleFactor(2.0); - st.assertRoundTrip(step, "junit allowEmptyResults: true, healthScaleFactor: 2.0, testResults: '**/target/surefire-reports/TEST-*.xml'"); + st.assertRoundTrip( + step, + "junit allowEmptyResults: true, healthScaleFactor: 2.0, testResults: '**/target/surefire-reports/TEST-*.xml'"); MockTestDataPublisher publisher = new MockTestDataPublisher("testing"); step.setTestDataPublishers(Collections.singletonList(publisher)); - st.assertRoundTrip(step, "junit allowEmptyResults: true, healthScaleFactor: 2.0, testDataPublishers: [[$class: 'MockTestDataPublisher', name: 'testing']], testResults: '**/target/surefire-reports/TEST-*.xml'"); + st.assertRoundTrip( + step, + "junit allowEmptyResults: true, healthScaleFactor: 2.0, testDataPublishers: [[$class: 'MockTestDataPublisher', name: 'testing']], testResults: '**/target/surefire-reports/TEST-*.xml'"); step.setSkipMarkingBuildUnstable(true); - st.assertRoundTrip(step, "junit allowEmptyResults: true, healthScaleFactor: 2.0, skipMarkingBuildUnstable: true, testDataPublishers: [[$class: 'MockTestDataPublisher', name: 'testing']], testResults: '**/target/surefire-reports/TEST-*.xml'"); + st.assertRoundTrip( + step, + "junit allowEmptyResults: true, healthScaleFactor: 2.0, skipMarkingBuildUnstable: true, testDataPublishers: [[$class: 'MockTestDataPublisher', name: 'testing']], testResults: '**/target/surefire-reports/TEST-*.xml'"); } @Issue("JENKINS-48250") @Test public void emptyFails() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "emptyFails"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - (Functions.isWindows() ? - " bat 'echo hi'\n" : - " sh 'echo hi'\n") + - " junit('*.xml')\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + (Functions.isWindows() ? " bat 'echo hi'\n" : " sh 'echo hi'\n") + + " junit('*.xml')\n" + + " }\n" + + "}\n", + true)); WorkflowRun r = j.scheduleBuild2(0).waitForStart(); rule.assertBuildStatus(Result.FAILURE, rule.waitForCompletion(r)); @@ -98,15 +103,14 @@ public void emptyFails() throws Exception { @Test public void allowEmpty() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "allowEmpty"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - (Functions.isWindows() ? - " bat 'echo hi'\n" : - " sh 'echo hi'\n") + - " def results = junit(testResults: '*.xml', allowEmptyResults: true)\n" + - " assert results.totalCount == 0\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + (Functions.isWindows() ? " bat 'echo hi'\n" : " sh 'echo hi'\n") + + " def results = junit(testResults: '*.xml', allowEmptyResults: true)\n" + + " assert results.totalCount == 0\n" + + " }\n" + + "}\n", + true)); WorkflowRun r = rule.buildAndAssertSuccess(j); assertNull(r.getAction(TestResultAction.class)); @@ -116,13 +120,15 @@ public void allowEmpty() throws Exception { @Test public void singleStep() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " def results = junit(testResults: '*.xml')\n" + // node id 7 - " assert results.totalCount == 6\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " def results = junit(testResults: '*.xml')\n" + + // node id 7 + " assert results.totalCount == 6\n" + + " }\n" + + "}\n", + true)); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-1463.xml"), "test-result.xml"); WorkflowRun r = rule.buildAndAssertSuccess(j); @@ -142,16 +148,19 @@ public void singleStep() throws Exception { @Test public void twoSteps() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "twoSteps"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'first-result.xml'\n" + - " touch 'second-result.xml'\n" + - " def first = junit(testResults: 'first-result.xml')\n" + // node id 7 - " def second = junit(testResults: 'second-result.xml')\n" + // node id 8 - " assert first.totalCount == 6\n" + - " assert second.totalCount == 1\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'first-result.xml'\n" + + " touch 'second-result.xml'\n" + + " def first = junit(testResults: 'first-result.xml')\n" + + // node id 7 + " def second = junit(testResults: 'second-result.xml')\n" + + // node id 8 + " assert first.totalCount == 6\n" + + " assert second.totalCount == 1\n" + + " }\n" + + "}\n", + true)); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-1463.xml"), "first-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-2874.xml"), "second-result.xml"); @@ -179,16 +188,20 @@ public void twoSteps() throws Exception { @Test public void twoStepsSkipOldReports() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "twoSteps"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - // yup very old file so we should not have flaky tests - " touch file:'first-result.xml', timestamp: 2\n" + - " def first = junit(testResults: 'first-result.xml', skipOldReports: true, allowEmptyResults: true)\n" + // node id 8 - " def second = junit(testResults: 'second-result.xml')\n" + // node id 9 - " assert first.totalCount == 0\n" + - " assert second.totalCount == 1\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + + // yup very old file so we should not have flaky tests + " touch file:'first-result.xml', timestamp: 2\n" + + " def first = junit(testResults: 'first-result.xml', skipOldReports: true, allowEmptyResults: true)\n" + + // node id 8 + " def second = junit(testResults: 'second-result.xml')\n" + + // node id 9 + " assert first.totalCount == 0\n" + + " assert second.totalCount == 1\n" + + " }\n" + + "}\n", + true)); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-1463.xml"), "first-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-2874.xml"), "second-result.xml"); @@ -213,29 +226,33 @@ public void twoStepsSkipOldReports() throws Exception { } } - @Test public void threeSteps() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "threeSteps"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - //" sleep 1\n" + - " touch 'first-result.xml'\n" + - " touch 'second-result.xml'\n" + - " touch 'third-result.xml'\n" + - " def first = junit(testResults: 'first-result.xml')\n" + // node id 7 - " def second = junit(testResults: 'second-result.xml')\n" + // node id 8 - " def third = junit(testResults: 'third-result.xml')\n" + // node id 9 - " assert first.totalCount == 6\n" + - " assert second.totalCount == 1\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + + // " sleep 1\n" + + " touch 'first-result.xml'\n" + + " touch 'second-result.xml'\n" + + " touch 'third-result.xml'\n" + + " def first = junit(testResults: 'first-result.xml')\n" + + // node id 7 + " def second = junit(testResults: 'second-result.xml')\n" + + // node id 8 + " def third = junit(testResults: 'third-result.xml')\n" + + // node id 9 + " assert first.totalCount == 6\n" + + " assert second.totalCount == 1\n" + + " }\n" + + "}\n", + true)); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-1463.xml"), "first-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-2874.xml"), "second-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-nested-testsuites.xml"), "third-result.xml"); - WorkflowRun r = rule.assertBuildStatus(Result.UNSTABLE, - rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + WorkflowRun r = rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); TestResultAction action = r.getAction(TestResultAction.class); assertNotNull(action); assertEquals(5, action.getResult().getSuites().size()); @@ -269,19 +286,19 @@ public void parallelInStage() throws Exception { copyToWorkspace(j, TestResultTest.class.getResource("junit-report-2874.xml"), "second-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-nested-testsuites.xml"), "third-result.xml"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'first-result.xml'\n" + - " touch 'second-result.xml'\n" + - " touch 'third-result.xml'\n" + - " parallel(a: { def first = junit(testResults: 'first-result.xml'); assert first.totalCount == 6 },\n" + - " b: { def second = junit(testResults: 'second-result.xml'); assert second.totalCount == 1 },\n" + - " c: { def third = junit(testResults: 'third-result.xml', keepTestNames: true); assert third.totalCount == 3 })\n" + - " }\n" + - "}\n", true - )); - WorkflowRun r = rule.assertBuildStatus(Result.UNSTABLE, - rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'first-result.xml'\n" + + " touch 'second-result.xml'\n" + + " touch 'third-result.xml'\n" + + " parallel(a: { def first = junit(testResults: 'first-result.xml'); assert first.totalCount == 6 },\n" + + " b: { def second = junit(testResults: 'second-result.xml'); assert second.totalCount == 1 },\n" + + " c: { def third = junit(testResults: 'third-result.xml', keepTestNames: true); assert third.totalCount == 3 })\n" + + " }\n" + + "}\n", + true)); + WorkflowRun r = rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); TestResultAction action = r.getAction(TestResultAction.class); assertNotNull(action); assertEquals(5, action.getResult().getSuites().size()); @@ -301,25 +318,26 @@ public void stageInParallel() throws Exception { copyToWorkspace(j, TestResultTest.class.getResource("junit-report-2874.xml"), "second-result.xml"); copyToWorkspace(j, TestResultTest.class.getResource("junit-report-nested-testsuites.xml"), "third-result.xml"); - j.setDefinition(new CpsFlowDefinition("stage('outer') {\n" + - " node {\n" + - " touch 'first-result.xml'\n" + - " touch 'second-result.xml'\n" + - " touch 'third-result.xml'\n" + - " parallel(a: { stage('a') { def first = junit(testResults: 'first-result.xml'); assert first.totalCount == 6 } },\n" + - " b: { stage('b') { def second = junit(testResults: 'second-result.xml'); assert second.totalCount == 1 } },\n" + - " c: { stage('d') { def third = junit(testResults: 'third-result.xml', keepTestNames: true); assert third.totalCount == 3 } })\n" + - " }\n" + - "}\n", true - )); - WorkflowRun r = rule.assertBuildStatus(Result.UNSTABLE, - rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + j.setDefinition(new CpsFlowDefinition( + "stage('outer') {\n" + " node {\n" + + " touch 'first-result.xml'\n" + + " touch 'second-result.xml'\n" + + " touch 'third-result.xml'\n" + + " parallel(a: { stage('a') { def first = junit(testResults: 'first-result.xml'); assert first.totalCount == 6 } },\n" + + " b: { stage('b') { def second = junit(testResults: 'second-result.xml'); assert second.totalCount == 1 } },\n" + + " c: { stage('d') { def third = junit(testResults: 'third-result.xml', keepTestNames: true); assert third.totalCount == 3 } })\n" + + " }\n" + + "}\n", + true)); + WorkflowRun r = rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); TestResultAction action = r.getAction(TestResultAction.class); assertNotNull(action); assertEquals(5, action.getResult().getSuites().size()); assertEquals(10, action.getTotalCount()); - // assertBranchResults looks to make sure the display names for tests are "(stageName) / (branchName) / (testName)" + // assertBranchResults looks to make sure the display names for tests are "(stageName) / (branchName) / + // (testName)" // That should still effectively be the case here, even though there's a stage inside each branch, because the // branch and nested stage have the same name. assertBranchResults(r, 1, 6, 0, "a", "outer", null, false); @@ -332,16 +350,17 @@ public void stageInParallel() throws Exception { @Test public void testTrends() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "testTrends"); - j.setDefinition(new CpsFlowDefinition("node {\n" + - " stage('first') {\n" + - " touch 'junit-report-testTrends-first.xml'\n" + - " def first = junit(testResults: \"junit-report-testTrends-first.xml\")\n" + - " }\n" + - " stage('second') {\n" + - " touch 'junit-report-testTrends-second.xml'\n" + - " def second = junit(testResults: \"junit-report-testTrends-second.xml\")\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "node {\n" + " stage('first') {\n" + + " touch 'junit-report-testTrends-first.xml'\n" + + " def first = junit(testResults: \"junit-report-testTrends-first.xml\")\n" + + " }\n" + + " stage('second') {\n" + + " touch 'junit-report-testTrends-second.xml'\n" + + " def second = junit(testResults: \"junit-report-testTrends-second.xml\")\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath firstFile = ws.child("junit-report-testTrends-first.xml"); FilePath secondFile = ws.child("junit-report-testTrends-second.xml"); @@ -358,7 +377,8 @@ public void testTrends() throws Exception { firstFile.copyFrom(JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-2.xml")); secondFile.copyFrom(JUnitResultsStepTest.class.getResource("junit-report-testTrends-second-2.xml")); - WorkflowRun secondRun = rule.assertBuildStatus(Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + WorkflowRun secondRun = rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); assertStageResults(secondRun, 1, 8, 3, "first"); assertStageResults(secondRun, 1, 1, 0, "second"); @@ -366,7 +386,8 @@ public void testTrends() throws Exception { firstFile.copyFrom(JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-3.xml")); secondFile.copyFrom(JUnitResultsStepTest.class.getResource("junit-report-testTrends-second-3.xml")); - WorkflowRun thirdRun = rule.assertBuildStatus(Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + WorkflowRun thirdRun = rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); assertStageResults(thirdRun, 1, 8, 3, "first"); assertStageResults(thirdRun, 1, 1, 0, "second"); TestResultAction thirdAction = thirdRun.getAction(TestResultAction.class); @@ -375,15 +396,18 @@ public void testTrends() throws Exception { for (CaseResult failed : thirdAction.getFailedTests()) { if (failed.getDisplayName() != null) { if (failed.getDisplayName().equals("first / testGetVendorFirmKeyForVendorRep")) { - assertEquals("first / org.twia.vendor.VendorManagerTest.testGetVendorFirmKeyForVendorRep", + assertEquals( + "first / org.twia.vendor.VendorManagerTest.testGetVendorFirmKeyForVendorRep", failed.getFullDisplayName()); assertEquals(2, failed.getFailedSince()); } else if (failed.getDisplayName().equals("first / testCreateAdjustingFirm")) { - assertEquals("first / org.twia.vendor.VendorManagerTest.testCreateAdjustingFirm", + assertEquals( + "first / org.twia.vendor.VendorManagerTest.testCreateAdjustingFirm", failed.getFullDisplayName()); assertEquals(2, failed.getFailedSince()); } else if (failed.getDisplayName().equals("first / testCreateVendorFirm")) { - assertEquals("first / org.twia.vendor.VendorManagerTest.testCreateVendorFirm", + assertEquals( + "first / org.twia.vendor.VendorManagerTest.testCreateVendorFirm", failed.getFullDisplayName()); assertEquals(3, failed.getFailedSince()); } else { @@ -397,30 +421,37 @@ public void testTrends() throws Exception { @Test public void currentBuildResultUnstable() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "currentBuildResultUnstable"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " def results = junit(testResults: '*.xml', skipOldReports: true)\n" + // node id 7 - " assert results.totalCount == 8\n" + - " assert currentBuild.result == 'UNSTABLE'\n" + - " }\n" + - "}\n", true)); - copyToWorkspace(j, JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-2.xml"), "test-result.xml"); - - rule.assertBuildStatus(Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " def results = junit(testResults: '*.xml', skipOldReports: true)\n" + + // node id 7 + " assert results.totalCount == 8\n" + + " assert currentBuild.result == 'UNSTABLE'\n" + + " }\n" + + "}\n", + true)); + copyToWorkspace( + j, JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-2.xml"), "test-result.xml"); + + rule.assertBuildStatus( + Result.UNSTABLE, rule.waitForCompletion(j.scheduleBuild2(0).waitForStart())); } @Test public void skipBuildUnstable() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "currentBuildResultUnstable"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " def results = junit(skipMarkingBuildUnstable: true, testResults: '*.xml')\n" + // node id 7 - " assert results.totalCount == 8\n" + - " assert currentBuild.result == null\n" + - " }\n" + - "}\n", true)); - copyToWorkspace(j, JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-2.xml"), "test-result.xml"); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " def results = junit(skipMarkingBuildUnstable: true, testResults: '*.xml')\n" + + // node id 7 + " assert results.totalCount == 8\n" + + " assert currentBuild.result == null\n" + + " }\n" + + "}\n", + true)); + copyToWorkspace( + j, JUnitResultsStepTest.class.getResource("junit-report-testTrends-first-2.xml"), "test-result.xml"); WorkflowRun r = rule.waitForCompletion(j.scheduleBuild2(0).waitForStart()); rule.assertBuildStatus(Result.SUCCESS, r); assertStageResults(r, 1, 8, 3, "first"); @@ -429,23 +460,25 @@ public void skipBuildUnstable() throws Exception { @Test public void ageResetSameTestSuiteName() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "p"); - j.setDefinition(new CpsFlowDefinition("stage('stage 1') {\n" + - " node {\n" + - " touch 'ageReset-1.xml'\n" + - " junit(testResults: '*-1.xml')\n" + - " }\n" + - "}\n" + - "stage('stage 2') {\n" + - " node {\n" + - " touch 'ageReset-2.xml'\n" + - " junit(testResults: '*-2.xml')\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('stage 1') {\n" + " node {\n" + + " touch 'ageReset-1.xml'\n" + + " junit(testResults: '*-1.xml')\n" + + " }\n" + + "}\n" + + "stage('stage 2') {\n" + + " node {\n" + + " touch 'ageReset-2.xml'\n" + + " junit(testResults: '*-2.xml')\n" + + " }\n" + + "}\n", + true)); copyToWorkspace(j, JUnitResultsStepTest.class.getResource("ageReset-1.xml"), "ageReset-1.xml"); copyToWorkspace(j, JUnitResultsStepTest.class.getResource("ageReset-2.xml"), "ageReset-2.xml"); WorkflowRun r = rule.waitForCompletion(j.scheduleBuild2(0).waitForStart()); rule.assertBuildStatus(Result.UNSTABLE, r); - assertEquals(2, r.getAction(TestResultAction.class).getResult().getSuites().size()); + assertEquals( + 2, r.getAction(TestResultAction.class).getResult().getSuites().size()); CaseResult caseResult = findCaseResult(r, "aClass.methodName"); assertNotNull(caseResult); assertEquals(1, caseResult.getAge()); @@ -468,36 +501,49 @@ private CaseResult findCaseResult(Run r, String name) { return null; } - private void copyToWorkspace(WorkflowJob j, URL source, String destination) throws IOException, InterruptedException { + private void copyToWorkspace(WorkflowJob j, URL source, String destination) + throws IOException, InterruptedException { FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = ws.child(destination); testFile.copyFrom(source); } - private static Predicate branchForName(final String name) { - return input -> input != null && - input.getAction(LabelAction.class) != null && - input.getAction(ThreadNameAction.class) != null && - name.equals(input.getAction(ThreadNameAction.class).getThreadName()); + return input -> input != null + && input.getAction(LabelAction.class) != null + && input.getAction(ThreadNameAction.class) != null + && name.equals(input.getAction(ThreadNameAction.class).getThreadName()); } private static Predicate stageForName(final String name) { - return input -> input instanceof StepStartNode && - ((StepStartNode) input).getDescriptor() instanceof StageStep.DescriptorImpl && - input.getDisplayName().equals(name); + return input -> input instanceof StepStartNode + && ((StepStartNode) input).getDescriptor() instanceof StageStep.DescriptorImpl + && input.getDisplayName().equals(name); } - public static void assertBranchResults(WorkflowRun run, int suiteCount, int testCount, int failCount, String branchName, String stageName, - String innerStageName) { + public static void assertBranchResults( + WorkflowRun run, + int suiteCount, + int testCount, + int failCount, + String branchName, + String stageName, + String innerStageName) { assertBranchResults(run, suiteCount, testCount, failCount, branchName, stageName, innerStageName, false); } - public static void assertBranchResults(WorkflowRun run, int suiteCount, int testCount, int failCount, String branchName, String stageName, - String innerStageName, boolean keepTestNames) { + public static void assertBranchResults( + WorkflowRun run, + int suiteCount, + int testCount, + int failCount, + String branchName, + String stageName, + String innerStageName, + boolean keepTestNames) { FlowExecution execution = run.getExecution(); DepthFirstScanner scanner = new DepthFirstScanner(); - BlockStartNode aBranch = (BlockStartNode)scanner.findFirstMatch(execution, branchForName(branchName)); + BlockStartNode aBranch = (BlockStartNode) scanner.findFirstMatch(execution, branchForName(branchName)); assertNotNull(aBranch); TestResult branchResult = assertBlockResults(run, suiteCount, testCount, failCount, aBranch); String namePrefix; @@ -515,15 +561,17 @@ public static void assertBranchResults(WorkflowRun run, int suiteCount, int test } } - public static void assertStageResults(WorkflowRun run, int suiteCount, int testCount, int failCount, String stageName) { + public static void assertStageResults( + WorkflowRun run, int suiteCount, int testCount, int failCount, String stageName) { FlowExecution execution = run.getExecution(); DepthFirstScanner scanner = new DepthFirstScanner(); - BlockStartNode aStage = (BlockStartNode)scanner.findFirstMatch(execution, stageForName(stageName)); + BlockStartNode aStage = (BlockStartNode) scanner.findFirstMatch(execution, stageForName(stageName)); assertNotNull(aStage); assertBlockResults(run, suiteCount, testCount, failCount, aStage); } - private static TestResult assertBlockResults(WorkflowRun run, int suiteCount, int testCount, int failCount, BlockStartNode blockNode) { + private static TestResult assertBlockResults( + WorkflowRun run, int suiteCount, int testCount, int failCount, BlockStartNode blockNode) { assertNotNull(blockNode); TestResultAction action = run.getAction(TestResultAction.class); @@ -555,7 +603,8 @@ private static TestResult assertBlockResults(WorkflowRun run, int suiteCount, in return aResult; } - private void assertExpectedResults(Run run, int suiteCount, int testCount, String... nodeIds) throws Exception { + private void assertExpectedResults(Run run, int suiteCount, int testCount, String... nodeIds) + throws Exception { TestResultAction action = run.getAction(TestResultAction.class); assertNotNull(action); @@ -566,12 +615,12 @@ private void assertExpectedResults(Run run, int suiteCount, int testCount, } private static List findJUnitSteps(BlockStartNode blockStart) { - return new DepthFirstScanner().filteredNodes( - Collections.singletonList(blockStart.getEndNode()), - Collections.singletonList(blockStart), - node -> node instanceof StepAtomNode && - ((StepAtomNode) node).getDescriptor() instanceof JUnitResultsStep.DescriptorImpl - ); + return new DepthFirstScanner() + .filteredNodes( + Collections.singletonList(blockStart.getEndNode()), + Collections.singletonList(blockStart), + node -> node instanceof StepAtomNode + && ((StepAtomNode) node).getDescriptor() instanceof JUnitResultsStep.DescriptorImpl); } private static BaseMatcher hasWarningAction() { @@ -580,6 +629,7 @@ private static BaseMatcher hasWarningAction() { public boolean matches(Object item) { return item instanceof FlowNode && ((FlowNode) item).getPersistentAction(WarningAction.class) != null; } + @Override public void describeTo(Description description) { description.appendText("a FlowNode with a WarningAction"); @@ -589,21 +639,28 @@ public void describeTo(Description description) { public static class MockTestDataPublisher extends TestDataPublisher { private final String name; + @DataBoundConstructor public MockTestDataPublisher(String name) { this.name = name; } + public String getName() { return name; } - @Override public TestResultAction.Data contributeTestData(Run run, FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) throws IOException, InterruptedException { + + @Override + public TestResultAction.Data contributeTestData( + Run run, FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) + throws IOException, InterruptedException { return null; } // Needed to make this extension available to all tests for {@link #testDescribableRoundTrip()} @TestExtension public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() { + @Override + public String getDisplayName() { return "MockTestDataPublisher"; } } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13CaseAction.java b/src/test/java/hudson/tasks/junit/rot13/Rot13CaseAction.java index a72d1067..7743f571 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13CaseAction.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13CaseAction.java @@ -5,5 +5,4 @@ public class Rot13CaseAction extends Rot13CipherAction { public Rot13CaseAction(String ciphertext) { super(ciphertext); } - } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13CipherAction.java b/src/test/java/hudson/tasks/junit/rot13/Rot13CipherAction.java index 6b75ed35..f4179659 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13CipherAction.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13CipherAction.java @@ -28,5 +28,4 @@ public String getUrlName() { public String getCiphertext() { return ciphertext; } - } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13ClassAction.java b/src/test/java/hudson/tasks/junit/rot13/Rot13ClassAction.java index 859a72b8..1351e603 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13ClassAction.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13ClassAction.java @@ -5,5 +5,4 @@ public class Rot13ClassAction extends Rot13CipherAction { public Rot13ClassAction(String ciphertext) { super(ciphertext); } - } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13PackageAction.java b/src/test/java/hudson/tasks/junit/rot13/Rot13PackageAction.java index 21fde55a..52c19df2 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13PackageAction.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13PackageAction.java @@ -5,5 +5,4 @@ public class Rot13PackageAction extends Rot13CipherAction { public Rot13PackageAction(String ciphertext) { super(ciphertext); } - } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13Publisher.java b/src/test/java/hudson/tasks/junit/rot13/Rot13Publisher.java index f1d8bedc..afac22a8 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13Publisher.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13Publisher.java @@ -34,12 +34,12 @@ public class Rot13Publisher extends TestDataPublisher { @DataBoundConstructor - public Rot13Publisher() { - } + public Rot13Publisher() {} @Override - public Data contributeTestData(Run build, FilePath workspace, Launcher launcher, TaskListener listener, - TestResult testResult) throws IOException, InterruptedException { + public Data contributeTestData( + Run build, FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) + throws IOException, InterruptedException { Map ciphertextMap = new HashMap<>(); for (PackageResult packageResult : testResult.getChildren()) { ciphertextMap.put(packageResult.getName(), rot13(packageResult.getName())); @@ -87,23 +87,22 @@ public List getTestAction(hudson.tasks.junit.TestObject t) { TestObject testObject = (TestObject) t; if (testObject instanceof CaseResult) { - return Collections.singletonList(new Rot13CaseAction(ciphertextMap.get( - ((CaseResult) testObject).getFullName()))); + return Collections.singletonList( + new Rot13CaseAction(ciphertextMap.get(((CaseResult) testObject).getFullName()))); } if (testObject instanceof ClassResult) { - return Collections.singletonList(new Rot13ClassAction(ciphertextMap.get( - ((ClassResult) testObject).getFullName()))); + return Collections.singletonList( + new Rot13ClassAction(ciphertextMap.get(((ClassResult) testObject).getFullName()))); } if (testObject instanceof PackageResult) { - return Collections.singletonList(new Rot13PackageAction(ciphertextMap.get( - ((PackageResult) testObject).getName()))); + return Collections.singletonList( + new Rot13PackageAction(ciphertextMap.get(((PackageResult) testObject).getName()))); } if (testObject instanceof TestResult) { return Collections.singletonList(new Rot13TestAction()); } return Collections.emptyList(); } - } @Extension @@ -114,7 +113,5 @@ public static class DescriptorImpl extends Descriptor { public String getDisplayName() { return "ROT13-encoded test case, class and package names"; } - } - } diff --git a/src/test/java/hudson/tasks/junit/rot13/Rot13TestAction.java b/src/test/java/hudson/tasks/junit/rot13/Rot13TestAction.java index 4c27664a..02afeef7 100644 --- a/src/test/java/hudson/tasks/junit/rot13/Rot13TestAction.java +++ b/src/test/java/hudson/tasks/junit/rot13/Rot13TestAction.java @@ -4,8 +4,7 @@ public class Rot13TestAction extends TestAction { - public Rot13TestAction() { - } + public Rot13TestAction() {} @Override public final String getIconFileName() { @@ -21,5 +20,4 @@ public final String getDisplayName() { public String getUrlName() { return null; } - } diff --git a/src/test/java/hudson/tasks/test/AggregatedTestResultPublisherTest.java b/src/test/java/hudson/tasks/test/AggregatedTestResultPublisherTest.java index 569d17ed..2e074f5d 100644 --- a/src/test/java/hudson/tasks/test/AggregatedTestResultPublisherTest.java +++ b/src/test/java/hudson/tasks/test/AggregatedTestResultPublisherTest.java @@ -30,19 +30,17 @@ public class AggregatedTestResultPublisherTest { public static final String TEST_PROJECT_NAME = "junit"; public static final String AGGREGATION_PROJECT_NAME = "aggregated"; + @Rule public JenkinsRule j = new JenkinsRule(); + private FreeStyleProject upstreamProject; private FreeStyleProject downstreamProject; private FreeStyleBuild build; private JenkinsRule.WebClient wc; - private static final String[] singleContents = { - "abcdef" - }; - private static final String[] singleFiles = { - "test.txt" - }; + private static final String[] singleContents = {"abcdef"}; + private static final String[] singleFiles = {"test.txt"}; private BuildPage buildPage; private ProjectPage projectPage; @@ -59,17 +57,21 @@ public void aggregatedTestResultsOnly() throws Exception { buildAndSetupPageObjects(); - projectPage.getLatestAggregatedTestReportLink() + projectPage + .getLatestAggregatedTestReportLink() .assertHasLatestAggregatedTestResultText() .assertHasTests() - .follow().hasLinkToTestResultOfBuild(TEST_PROJECT_NAME, 1); + .follow() + .hasLinkToTestResultOfBuild(TEST_PROJECT_NAME, 1); projectPage.assertNoTestReportLink(); - buildPage.getAggregatedTestReportLink() + buildPage + .getAggregatedTestReportLink() .assertHasAggregatedTestResultText() .assertHasTests() - .follow().hasLinkToTestResultOfBuild(TEST_PROJECT_NAME, 1); + .follow() + .hasLinkToTestResultOfBuild(TEST_PROJECT_NAME, 1); buildPage.assertNoTestReportLink(); } @@ -81,20 +83,20 @@ public void testResultsOnly() throws Exception { buildAndSetupPageObjects(); - projectPage.getLatestTestReportLink() + projectPage + .getLatestTestReportLink() .assertHasLatestTestResultText() .assertHasTests() .follow(); - projectPage.getLatestAggregatedTestReportLink() + projectPage + .getLatestAggregatedTestReportLink() .assertHasLatestAggregatedTestResultText() .assertNoTests() .follow(); - buildPage.getTestReportLink() - .assertHasTestResultText() - .assertHasTests() - .follow(); - buildPage.getAggregatedTestReportLink() + buildPage.getTestReportLink().assertHasTestResultText().assertHasTests().follow(); + buildPage + .getAggregatedTestReportLink() .assertHasAggregatedTestResultText() .assertNoTests() .follow(); @@ -108,20 +110,20 @@ public void testResultsAndAggregatedTestResults() throws Exception { buildAndSetupPageObjects(); - projectPage.getLatestTestReportLink() + projectPage + .getLatestTestReportLink() .assertHasLatestTestResultText() .assertHasTests() .follow(); - projectPage.getLatestAggregatedTestReportLink() + projectPage + .getLatestAggregatedTestReportLink() .assertHasLatestAggregatedTestResultText() .assertHasTests() .follow(); - buildPage.getTestReportLink() - .assertHasTestResultText() - .assertHasTests() - .follow(); - buildPage.getAggregatedTestReportLink() + buildPage.getTestReportLink().assertHasTestResultText().assertHasTests().follow(); + buildPage + .getAggregatedTestReportLink() .assertHasAggregatedTestResultText() .assertHasTests() .follow() @@ -143,11 +145,11 @@ private void build(int numberOfDownstreamBuilds) throws Exception { j.waitUntilNoActivity(); List> downstreamBuilds = StreamSupport.stream( - build.getDownstreamBuilds(downstreamProject).spliterator(), false).collect(Collectors.toList()); + build.getDownstreamBuilds(downstreamProject).spliterator(), false) + .collect(Collectors.toList()); assertThat(downstreamBuilds, hasSize(numberOfDownstreamBuilds)); } - private void createUpstreamProjectWithTests() throws Exception { createUpstreamProjectWithNoTests(); addJUnitResultArchiver(upstreamProject); @@ -171,7 +173,9 @@ private void createDownstreamProjectWithNoTests() throws Exception { downstreamProject.setQuietPeriod(0); addFingerprinterToProject(downstreamProject, singleContents, singleFiles); - upstreamProject.getPublishersList().add(new BuildTrigger(Collections.singletonList(downstreamProject), Result.SUCCESS)); + upstreamProject + .getPublishersList() + .add(new BuildTrigger(Collections.singletonList(downstreamProject), Result.SUCCESS)); upstreamProject.getPublishersList().add(new AggregatedTestResultPublisher(null)); j.jenkins.rebuildDependencyGraph(); @@ -183,7 +187,8 @@ private void addJUnitResultArchiver(FreeStyleProject project) { project.getBuildersList().add(new TouchBuilder()); } - private void addFingerprinterToProject(FreeStyleProject project, String[] contents, String[] files) throws Exception { + private void addFingerprinterToProject(FreeStyleProject project, String[] contents, String[] files) + throws Exception { StringBuilder targets = new StringBuilder(); for (int i = 0; i < contents.length; i++) { String command = "echo $BUILD_NUMBER " + contents[i] + " > " + files[i]; diff --git a/src/test/java/hudson/tasks/test/BuildStatusSummaryTest.java b/src/test/java/hudson/tasks/test/BuildStatusSummaryTest.java index cc17e5e2..b568ee79 100644 --- a/src/test/java/hudson/tasks/test/BuildStatusSummaryTest.java +++ b/src/test/java/hudson/tasks/test/BuildStatusSummaryTest.java @@ -16,13 +16,14 @@ /** * Tests {@link Run#getBuildStatusSummary()}. - * + * * @author kutzi */ @SuppressWarnings("rawtypes") public class BuildStatusSummaryTest { - @Rule public JenkinsRule r = new JenkinsRule(); // to load AbstractTestResultAction.Summarizer + @Rule + public JenkinsRule r = new JenkinsRule(); // to load AbstractTestResultAction.Summarizer private Run build; private Run prevBuild; @@ -31,32 +32,31 @@ public class BuildStatusSummaryTest { public void before() { mockBuilds(Run.class); } - + private void mockBuilds(Class buildClass) { this.build = mock(buildClass); this.prevBuild = mock(buildClass); - + when(this.build.getPreviousBuild()).thenReturn(prevBuild); - + when(this.build.getBuildStatusSummary()).thenCallRealMethod(); } - + @Test public void testBuildGotAFailingTest() { // previous build has no tests at all mockBuilds(AbstractBuild.class); - + when(this.build.getResult()).thenReturn(Result.UNSTABLE); when(this.prevBuild.getResult()).thenReturn(Result.SUCCESS); - + buildHasTestResult((AbstractBuild) this.build, 1); - + Run.Summary summary = this.build.getBuildStatusSummary(); - + assertTrue(summary.isWorse); assertEquals(Messages.Run_Summary_TestFailures(1), summary.message); - - + // same thing should happen if previous build has tests, but no failing ones: buildHasTestResult((AbstractBuild) this.prevBuild, 0); summary = this.build.getBuildStatusSummary(); @@ -72,7 +72,8 @@ public void testBuildGotNoTests() { when(this.build.getResult()).thenReturn(Result.UNSTABLE); when(this.prevBuild.getResult()).thenReturn(Result.UNSTABLE); // Null test result action recorded - when(((AbstractBuild) this.build).getAction(AbstractTestResultAction.class)).thenReturn(null); + when(((AbstractBuild) this.build).getAction(AbstractTestResultAction.class)) + .thenReturn(null); Run.Summary summary = this.build.getBuildStatusSummary(); @@ -85,59 +86,59 @@ public void testBuildGotNoTests() { assertFalse(summary.isWorse); assertEquals(hudson.model.Messages.Run_Summary_Unstable(), summary.message); } - + @Test public void testBuildEqualAmountOfTestsFailing() { mockBuilds(AbstractBuild.class); - + when(this.build.getResult()).thenReturn(Result.UNSTABLE); when(this.prevBuild.getResult()).thenReturn(Result.UNSTABLE); - + buildHasTestResult((AbstractBuild) this.prevBuild, 1); buildHasTestResult((AbstractBuild) this.build, 1); - + Run.Summary summary = this.build.getBuildStatusSummary(); - + assertFalse(summary.isWorse); assertEquals(Messages.Run_Summary_TestsStillFailing(1), summary.message); } - + @Test public void testBuildGotMoreFailingTests() { mockBuilds(AbstractBuild.class); - + when(this.build.getResult()).thenReturn(Result.UNSTABLE); when(this.prevBuild.getResult()).thenReturn(Result.UNSTABLE); - + buildHasTestResult((AbstractBuild) this.prevBuild, 1); buildHasTestResult((AbstractBuild) this.build, 2); - + Run.Summary summary = this.build.getBuildStatusSummary(); - + assertTrue(summary.isWorse); assertEquals(Messages.Run_Summary_MoreTestsFailing(1, 2), summary.message); } - + @Test public void testBuildGotLessFailingTests() { mockBuilds(AbstractBuild.class); - + when(this.build.getResult()).thenReturn(Result.UNSTABLE); when(this.prevBuild.getResult()).thenReturn(Result.UNSTABLE); - + buildHasTestResult((AbstractBuild) this.prevBuild, 2); buildHasTestResult((AbstractBuild) this.build, 1); - + Run.Summary summary = this.build.getBuildStatusSummary(); - + assertFalse(summary.isWorse); assertEquals(Messages.Run_Summary_LessTestsFailing(1, 1), summary.message); } - + private void buildHasTestResult(AbstractBuild build, int failedTests) { AbstractTestResultAction testResult = mock(AbstractTestResultAction.class); when(testResult.getFailCount()).thenReturn(failedTests); - + when(build.getAction(AbstractTestResultAction.class)).thenReturn(testResult); } } diff --git a/src/test/java/hudson/tasks/test/TestObjectTest.java b/src/test/java/hudson/tasks/test/TestObjectTest.java index 7a7a0099..005bf71e 100644 --- a/src/test/java/hudson/tasks/test/TestObjectTest.java +++ b/src/test/java/hudson/tasks/test/TestObjectTest.java @@ -18,8 +18,7 @@ public class TestObjectTest { public static class TestObjectImpl extends TestObject { - public TestObjectImpl() { - } + public TestObjectImpl() {} @Override public TestObject getParent() { @@ -71,7 +70,7 @@ public String getDisplayName() { public void testSafe() { String name = "Foo#approve! is by approve_on_foo?xyz/\\: 50%"; String encoded = TestObject.safe(name); - + Assert.assertFalse(encoded.contains("#")); Assert.assertFalse(encoded.contains("?")); Assert.assertFalse(encoded.contains("\\")); @@ -82,13 +81,15 @@ public void testSafe() { Assert.assertFalse(encoded.contains(">")); } - @Test public void uniquifyName() { + @Test + public void uniquifyName() { for (int i = 0; i < 2; i++) { // different parents final List ts = new ArrayList<>(); for (int j = 0; j < 10; j++) { final String name = "t" + (int) Math.sqrt(j); // partly unique names ts.add(new SimpleCaseResult() { - @Override public String getSafeName() { + @Override + public String getSafeName() { return uniquifyName(ts, name); } }); @@ -116,5 +117,4 @@ public void getUrlShouldBeRelativeToContextRoot() { doReturn(run).when(testObject).getRun(); assertEquals("job/abc/123/testReport/dummy", testObject.getUrl()); } - } diff --git a/src/test/java/hudson/tasks/test/TestReportUiTest.java b/src/test/java/hudson/tasks/test/TestReportUiTest.java index 4aeb59fa..6d0bd53d 100644 --- a/src/test/java/hudson/tasks/test/TestReportUiTest.java +++ b/src/test/java/hudson/tasks/test/TestReportUiTest.java @@ -76,16 +76,20 @@ public void handleAlert(Page page, String message) { String duration3_3sec = Util.getTimeSpanString((long) (3.377 * 1000)); String duration2_5sec = Util.getTimeSpanString((long) (2.502 * 1000)); - Assert.assertNotNull(pg.getFirstByXPath("//td[contains(text(),'" + duration3_3sec + "')][contains(@class,'no-wrap')]")); + Assert.assertNotNull( + pg.getFirstByXPath("//td[contains(text(),'" + duration3_3sec + "')][contains(@class,'no-wrap')]")); pg = wc.getPage(b, "testReport/org.twia.vendor"); - Assert.assertNotNull(pg.getFirstByXPath("//td[contains(text(),'" + duration3_3sec + "')][contains(@class,'no-wrap')]")); - Assert.assertNotNull(pg.getFirstByXPath("//td[contains(text(),'" + duration14sec + "')][contains(@class,'no-wrap')]")); + Assert.assertNotNull( + pg.getFirstByXPath("//td[contains(text(),'" + duration3_3sec + "')][contains(@class,'no-wrap')]")); + Assert.assertNotNull( + pg.getFirstByXPath("//td[contains(text(),'" + duration14sec + "')][contains(@class,'no-wrap')]")); pg = wc.getPage(b, "testReport/org.twia.vendor/VendorManagerTest"); - Assert.assertNotNull(pg.getFirstByXPath("//td[contains(text(),'" + duration2_5sec + "')][contains(@class,'no-wrap')]")); + Assert.assertNotNull( + pg.getFirstByXPath("//td[contains(text(),'" + duration2_5sec + "')][contains(@class,'no-wrap')]")); } /** @@ -97,9 +101,11 @@ private FreeStyleBuild configureTestBuild(String projectName) throws Exception { p.getBuildersList().add(new TestBuilder() { @Override @SuppressWarnings("null") - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - build.getWorkspace().child("junit.xml").copyFrom( - getClass().getResource("/hudson/tasks/junit/junit-report-20090516.xml")); + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + throws InterruptedException, IOException { + build.getWorkspace() + .child("junit.xml") + .copyFrom(getClass().getResource("/hudson/tasks/junit/junit-report-20090516.xml")); return true; } }); diff --git a/src/test/java/hudson/tasks/test/TestResultExtensionTest.java b/src/test/java/hudson/tasks/test/TestResultExtensionTest.java index c40248a2..e1081d28 100644 --- a/src/test/java/hudson/tasks/test/TestResultExtensionTest.java +++ b/src/test/java/hudson/tasks/test/TestResultExtensionTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -39,7 +39,7 @@ /** * A test case to make sure that the TestResult extension mechanism - * is working properly. + * is working properly. */ public class TestResultExtensionTest { @@ -60,10 +60,9 @@ public void testTrivialRecorder() throws Exception { assertNotNull("parent action should have an owner", action.run); Object resultObject = action.getResult(); assertNotNull("we should have a result"); - assertTrue("result should be an TestResult", - resultObject instanceof TestResult); + assertTrue("result should be an TestResult", resultObject instanceof TestResult); TestResult result = (TestResult) resultObject; - Run ownerBuild = result.getRun(); + Run ownerBuild = result.getRun(); assertNotNull("we should have an owner", ownerBuild); assertNotNull("we should have a list of test actions", result.getTestActions()); @@ -73,9 +72,5 @@ public void testTrivialRecorder() throws Exception { j.assertGoodStatus(projectPage); HtmlPage testReportPage = wc.getPage(project, "/lastBuild/testReport/"); j.assertGoodStatus(testReportPage); - - } } - - diff --git a/src/test/java/hudson/tasks/test/TrivialTestResult.java b/src/test/java/hudson/tasks/test/TrivialTestResult.java index ea328fca..7fd8ce6e 100644 --- a/src/test/java/hudson/tasks/test/TrivialTestResult.java +++ b/src/test/java/hudson/tasks/test/TrivialTestResult.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -31,11 +31,9 @@ @Extension public class TrivialTestResult extends SimpleCaseResult { - /** A list only containing this one result. Useful for returning * from getXXXTests() methods. */ - /** A silly world that is all the data associated with this test result */ private String sillyWord; @@ -51,5 +49,4 @@ public TrivialTestResult(String sillyWord) { public String getSillyWord() { return sillyWord; } - } diff --git a/src/test/java/hudson/tasks/test/TrivialTestResultAction.java b/src/test/java/hudson/tasks/test/TrivialTestResultAction.java index f51f50d2..de9d0d94 100644 --- a/src/test/java/hudson/tasks/test/TrivialTestResultAction.java +++ b/src/test/java/hudson/tasks/test/TrivialTestResultAction.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -50,7 +50,7 @@ protected TrivialTestResultAction(TrivialTestResult result) { */ @Override public int getFailCount() { - return 0; // (FIXME: generated) + return 0; // (FIXME: generated) } /** @@ -58,7 +58,7 @@ public int getFailCount() { */ @Override public int getTotalCount() { - return 0; // (FIXME: generated) + return 0; // (FIXME: generated) } /** @@ -84,6 +84,7 @@ public Object getResult() { * {@link org.kohsuke.stapler.StaplerProxy} look-up is done and {@code this} object * processes the request. */ + @Override public Object getTarget() { return getResult(); } diff --git a/src/test/java/hudson/tasks/test/TrivialTestResultRecorder.java b/src/test/java/hudson/tasks/test/TrivialTestResultRecorder.java index 657cbce1..64489e6e 100644 --- a/src/test/java/hudson/tasks/test/TrivialTestResultRecorder.java +++ b/src/test/java/hudson/tasks/test/TrivialTestResultRecorder.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2009, Yahoo!, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -40,8 +40,7 @@ */ public class TrivialTestResultRecorder extends Recorder implements Serializable { @Override - public boolean perform(AbstractBuild build, - Launcher launcher, BuildListener listener) + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { System.out.println("performing TrviialTestResultRecorder"); listener.getLogger().println("perfoming TrivialTestResultRecorder"); @@ -54,12 +53,13 @@ public boolean perform(AbstractBuild build, return true; } + @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } @Extension - public static class DescriptorImpl extends BuildStepDescriptor { + public static class DescriptorImpl extends BuildStepDescriptor { /** * Returns true if this task is applicable to the given project. @@ -77,8 +77,7 @@ public boolean isApplicable(Class jobType) { */ @Override public String getDisplayName() { - return "trivialtestrecorder"; + return "trivialtestrecorder"; } } - } diff --git a/src/test/java/hudson/tasks/test/helper/AbstractPage.java b/src/test/java/hudson/tasks/test/helper/AbstractPage.java index 2360a734..2980bb9d 100644 --- a/src/test/java/hudson/tasks/test/helper/AbstractPage.java +++ b/src/test/java/hudson/tasks/test/helper/AbstractPage.java @@ -23,6 +23,7 @@ public AbstractPage(HtmlPage htmlPage) { public HtmlAnchor getTestReportAnchor(String testUrl) throws IOException, SAXException { return htmlPage.getAnchorByHref(getHrefFromTestUrl(testUrl)); } + public void assertNoLink(String url) { List anchors = htmlPage.getAnchors(); boolean found = false; diff --git a/src/test/java/hudson/tasks/test/helper/AbstractTestResultLink.java b/src/test/java/hudson/tasks/test/helper/AbstractTestResultLink.java index d8686bd0..5d040d7c 100644 --- a/src/test/java/hudson/tasks/test/helper/AbstractTestResultLink.java +++ b/src/test/java/hudson/tasks/test/helper/AbstractTestResultLink.java @@ -16,6 +16,7 @@ public AbstractTestResultLink(HtmlAnchor testResultLink) { public String getResultText() { return testResultLink.getNextSibling().asNormalizedText(); } + public T assertNoTests() { assertThat(getResultText(), containsString("no tests")); return castToConcreteType(); @@ -35,5 +36,4 @@ public TestResultsPage follow() throws Exception { private T castToConcreteType() { return (T) this; } - } diff --git a/src/test/java/hudson/tasks/test/helper/BuildPage.java b/src/test/java/hudson/tasks/test/helper/BuildPage.java index b1da888d..7bdeaab7 100644 --- a/src/test/java/hudson/tasks/test/helper/BuildPage.java +++ b/src/test/java/hudson/tasks/test/helper/BuildPage.java @@ -15,7 +15,6 @@ protected String getHrefFromTestUrl(String testUrl) { return testUrl + "/"; } - public TestResultLink getAggregatedTestReportLink() throws IOException, SAXException { return new TestResultLink(getTestReportAnchor(AGGREGATED_TEST_REPORT_URL)); } diff --git a/src/test/java/hudson/tasks/test/helper/ProjectPage.java b/src/test/java/hudson/tasks/test/helper/ProjectPage.java index ca1b3861..81694f01 100644 --- a/src/test/java/hudson/tasks/test/helper/ProjectPage.java +++ b/src/test/java/hudson/tasks/test/helper/ProjectPage.java @@ -10,7 +10,6 @@ public ProjectPage(HtmlPage projectPage) { super(projectPage); } - public LatestTestResultLink getLatestTestReportLink() throws IOException, SAXException { return new LatestTestResultLink(getTestReportAnchor(TEST_REPORT_URL)); } @@ -19,6 +18,7 @@ public LatestTestResultLink getLatestAggregatedTestReportLink() throws IOExcepti return new LatestTestResultLink(getTestReportAnchor(AGGREGATED_TEST_REPORT_URL)); } + @Override protected String getHrefFromTestUrl(String testUrl) { return "lastCompletedBuild/" + testUrl + "/"; } @@ -30,5 +30,4 @@ public void assertNoTestReportLink() { public void assertNoAggregatedTestReportLink() { assertNoLink(AGGREGATED_TEST_REPORT_URL); } - } diff --git a/src/test/java/hudson/tasks/test/helper/TestResultLink.java b/src/test/java/hudson/tasks/test/helper/TestResultLink.java index 6d850f7c..3a875fd8 100644 --- a/src/test/java/hudson/tasks/test/helper/TestResultLink.java +++ b/src/test/java/hudson/tasks/test/helper/TestResultLink.java @@ -23,5 +23,4 @@ public TestResultLink assertHasAggregatedTestResultText() { assertThat(testResultLink.getTextContent(), containsString(AGGREGATED_TEST_RESULT_STRING)); return this; } - } diff --git a/src/test/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisherTest.java b/src/test/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisherTest.java index eb5a27af..3d828a7c 100644 --- a/src/test/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisherTest.java +++ b/src/test/java/io/jenkins/plugins/junit/checks/JUnitChecksPublisherTest.java @@ -27,7 +27,7 @@ public class JUnitChecksPublisherTest { public final JenkinsRule rule = new JenkinsRule(); @TestExtension - public final static CapturingChecksPublisher.Factory PUBLISHER_FACTORY = new CapturingChecksPublisher.Factory(); + public static final CapturingChecksPublisher.Factory PUBLISHER_FACTORY = new CapturingChecksPublisher.Factory(); @After public void clearPublishedChecks() { @@ -48,13 +48,14 @@ private List getDetails() { @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsPassingTestResults() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " def results = junit(testResults: '*.xml')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " def results = junit(testResults: '*.xml')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-1463.xml")); @@ -70,19 +71,19 @@ public void extractChecksDetailsPassingTestResults() throws Exception { assertThat(output.getTitle().get(), is("passed: 6")); assertThat(output.getText().get(), is("")); - } @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsFailingSingleTestResult() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " def results = junit(testResults: '*.xml')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " def results = junit(testResults: '*.xml')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-errror-details.xml")); @@ -97,19 +98,19 @@ public void extractChecksDetailsFailingSingleTestResult() throws Exception { ChecksOutput output = checksDetails.getOutput().get(); assertThat(output.getTitle().get(), is("some.package.somewhere.WhooHoo.testHudsonReporting failed")); - } @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsFailingMultipleTests() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " def results = junit(testResults: '*.xml')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " def results = junit(testResults: '*.xml')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-20090516.xml")); @@ -124,20 +125,20 @@ public void extractChecksDetailsFailingMultipleTests() throws Exception { ChecksOutput output = checksDetails.getOutput().get(); assertThat(output.getTitle().get(), is("failed: 3, passed: 5")); - } @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsCustomCheckName() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " def results = junit(testResults: '*.xml', checksName: 'Custom Checks Name')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " def results = junit(testResults: '*.xml', checksName: 'Custom Checks Name')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-1463.xml")); @@ -151,16 +152,16 @@ public void extractChecksDetailsCustomCheckName() throws Exception { assertThat(checksDetails.getName().get(), is("Custom Checks Name")); } - @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsNoStageContext() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("node {\n" + - " touch 'test-result.xml'\n" + - " def results = junit(testResults: '*.xml')\n" + - " assert results.totalCount == 6\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "node {\n" + " touch 'test-result.xml'\n" + + " def results = junit(testResults: '*.xml')\n" + + " assert results.totalCount == 6\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-1463.xml")); @@ -176,12 +177,13 @@ public void extractChecksDetailsNoStageContext() throws Exception { @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsNestedStages() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') { stage('second') {\n" + - " node {\n" + - " def results = junit(testResults: '*.xml')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - "}}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') { stage('second') {\n" + " node {\n" + + " def results = junit(testResults: '*.xml')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + "}}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); testFile.copyFrom(TestResultTest.class.getResource("junit-report-1463.xml")); @@ -197,12 +199,13 @@ public void extractChecksDetailsNestedStages() throws Exception { @SuppressWarnings("OptionalGetWithoutIsPresent") public void extractChecksDetailsEmptySuite() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " def results = junit(testResults: '*.xml', allowEmptyResults: true)\n" + - " assert results.totalCount == 0\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " def results = junit(testResults: '*.xml', allowEmptyResults: true)\n" + + " assert results.totalCount == 0\n" + + " }\n" + + "}\n", + true)); rule.buildAndAssertSuccess(j); @@ -220,15 +223,16 @@ public void extractChecksDetailsEmptySuite() throws Exception { @SuppressWarnings("OptionalGetWithoutIsPresent") public void withChecksContext() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " withChecks('With Checks') {\n"+ - " def results = junit '*.xml'\n" + - " assert results.totalCount == 6\n" + - " }\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " withChecks('With Checks') {\n" + + " def results = junit '*.xml'\n" + + " assert results.totalCount == 6\n" + + " }\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); @@ -247,25 +251,25 @@ public void withChecksContext() throws Exception { assertThat(checksDetails.get(1).getName().get(), is("With Checks")); assertThat(checksDetails.get(1).getStatus(), is(ChecksStatus.COMPLETED)); assertThat(checksDetails.get(1).getConclusion(), is(ChecksConclusion.SUCCESS)); - } @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void withChecksContextDeclarative() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("pipeline {\n" + - " agent any\n" + - " stages {\n" + - " stage('first') {\n" + - " steps {\n" + - " withChecks('With Checks') {\n" + - " junit(testResults: '*.xml')\n" + - " }\n" + - " }\n" + - " }\n" + - " }\n" + - "}", true)); + j.setDefinition(new CpsFlowDefinition( + "pipeline {\n" + " agent any\n" + + " stages {\n" + + " stage('first') {\n" + + " steps {\n" + + " withChecks('With Checks') {\n" + + " junit(testResults: '*.xml')\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); @@ -284,22 +288,22 @@ public void withChecksContextDeclarative() throws Exception { assertThat(checksDetails.get(1).getName().get(), is("With Checks")); assertThat(checksDetails.get(1).getStatus(), is(ChecksStatus.COMPLETED)); assertThat(checksDetails.get(1).getConclusion(), is(ChecksConclusion.SUCCESS)); - } @Test @SuppressWarnings("OptionalGetWithoutIsPresent") public void withChecksContextWithCustomName() throws Exception { WorkflowJob j = rule.jenkins.createProject(WorkflowJob.class, "singleStep"); - j.setDefinition(new CpsFlowDefinition("stage('first') {\n" + - " node {\n" + - " touch 'test-result.xml'\n" + - " withChecks('With Checks') {\n"+ - " def results = junit(testResults: '*.xml', checksName: 'Custom Checks Name')\n" + - " assert results.totalCount == 6\n" + - " }\n" + - " }\n" + - "}\n", true)); + j.setDefinition(new CpsFlowDefinition( + "stage('first') {\n" + " node {\n" + + " touch 'test-result.xml'\n" + + " withChecks('With Checks') {\n" + + " def results = junit(testResults: '*.xml', checksName: 'Custom Checks Name')\n" + + " assert results.totalCount == 6\n" + + " }\n" + + " }\n" + + "}\n", + true)); FilePath ws = rule.jenkins.getWorkspaceFor(j); FilePath testFile = Objects.requireNonNull(ws).child("test-result.xml"); @@ -318,7 +322,5 @@ public void withChecksContextWithCustomName() throws Exception { assertThat(checksDetails.get(1).getName().get(), is("Custom Checks Name")); assertThat(checksDetails.get(1).getStatus(), is(ChecksStatus.COMPLETED)); assertThat(checksDetails.get(1).getConclusion(), is(ChecksConclusion.SUCCESS)); - } - } diff --git a/src/test/java/io/jenkins/plugins/junit/storage/TestResultStorageJunitTest.java b/src/test/java/io/jenkins/plugins/junit/storage/TestResultStorageJunitTest.java index e29ac42a..e14251a5 100644 --- a/src/test/java/io/jenkins/plugins/junit/storage/TestResultStorageJunitTest.java +++ b/src/test/java/io/jenkins/plugins/junit/storage/TestResultStorageJunitTest.java @@ -103,16 +103,19 @@ public class TestResultStorageJunitTest { private static final Logger LOGGER = Logger.getLogger(TestResultStorageJunitTest.class.getName()); - - @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); - - @Rule public JenkinsRule r = new JenkinsRule(); + + @ClassRule + public static BuildWatcher buildWatcher = new BuildWatcher(); + + @Rule + public JenkinsRule r = new JenkinsRule(); /** * Need {@link LocalH2Database#getAutoServer} so that {@link Impl} can make connections from an agent JVM. * @see Automatic Mixed Mode */ - @Before public void autoServer() throws Exception { + @Before + public void autoServer() throws Exception { GlobalDatabaseConfiguration gdc = GlobalDatabaseConfiguration.get(); gdc.setDatabase(null); LocalH2Database.setDefaultGlobalDatabase(); @@ -121,29 +124,34 @@ public class TestResultStorageJunitTest { JunitTestResultStorageConfiguration.get().setStorage(new Impl()); } - @Test public void smokes() throws Exception { + @Test + public void smokes() throws Exception { DumbSlave remote = r.createOnlineSlave(Label.get("remote")); - //((Channel) remote.getChannel()).addListener(new LoggingChannelListener(Logger.getLogger(TestResultStorageTest.class.getName()), Level.INFO)); + // ((Channel) remote.getChannel()).addListener(new + // LoggingChannelListener(Logger.getLogger(TestResultStorageTest.class.getName()), Level.INFO)); WorkflowJob p = r.createProject(WorkflowJob.class, "p"); p.setDefinition(new CpsFlowDefinition( - "node('remote') {\n" + - " writeFile file: 'x.xml', text: '''" + - "" + - "" + - "" + - "'''\n" + - " def s = junit testResults: 'x.xml', skipPublishingChecks: true\n" + - " echo(/summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + - " writeFile file: 'x.xml', text: '''" + - "" + - "'''\n" + - " s = junit testResults: 'x.xml', skipPublishingChecks: true\n" + - " echo(/next summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + - "}", true)); + "node('remote') {\n" + " writeFile file: 'x.xml', text: '''" + + "" + + "" + + "" + + "'''\n" + + " def s = junit testResults: 'x.xml', skipPublishingChecks: true\n" + + " echo(/summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + + " writeFile file: 'x.xml', text: '''" + + "" + + "'''\n" + + " s = junit testResults: 'x.xml', skipPublishingChecks: true\n" + + " echo(/next summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + + "}", + true)); WorkflowRun b = p.scheduleBuild2(0).get(); - try (Connection connection = Objects.requireNonNull(GlobalDatabaseConfiguration.get().getDatabase()).getDataSource().getConnection(); - PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + Impl.CASE_RESULTS_TABLE); - ResultSet result = statement.executeQuery()) { + try (Connection connection = Objects.requireNonNull( + GlobalDatabaseConfiguration.get().getDatabase()) + .getDataSource() + .getConnection(); + PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + Impl.CASE_RESULTS_TABLE); + ResultSet result = statement.executeQuery()) { printResultSet(result); } // TODO verify table structure @@ -153,7 +161,9 @@ public class TestResultStorageJunitTest { assertFalse(new File(b.getRootDir(), "junitResult.xml").isFile()); { String buildXml = FileUtils.readFileToString(new File(b.getRootDir(), "build.xml")); - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(buildXml.getBytes(StandardCharsets.UTF_8))); + Document doc = DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(buildXml.getBytes(StandardCharsets.UTF_8))); NodeList testResultActionList = doc.getElementsByTagName("hudson.tasks.junit.TestResultAction"); assertEquals(buildXml, 1, testResultActionList.getLength()); Element testResultAction = (Element) testResultActionList.item(0); @@ -200,7 +210,7 @@ public class TestResultStorageJunitTest { assertEquals(1, passedTests.size()); assertEquals("Klazz", passedTests.get(0).getClassName()); assertEquals("test2", passedTests.get(0).getName()); - + PackageResult another = a.getResult().byPackage("another"); List packageFailedTests = another.getFailedTests(); assertEquals(1, packageFailedTests.size()); @@ -217,7 +227,8 @@ public class TestResultStorageJunitTest { assertEquals(1, rootPassedTests.size()); assertEquals("Klazz", rootPassedTests.get(0).getClassName()); - TestResultImpl pluggableStorage = Objects.requireNonNull(a.getResult().getPluggableStorage()); + TestResultImpl pluggableStorage = + Objects.requireNonNull(a.getResult().getPluggableStorage()); List trendTestResultSummary = pluggableStorage.getTrendTestResultSummary(); assertThat(trendTestResultSummary, hasSize(1)); TestResultSummary testResultSummary = trendTestResultSummary.get(0).getTestResultSummary(); @@ -229,16 +240,20 @@ public class TestResultStorageJunitTest { int countOfBuildsWithTestResults = pluggableStorage.getCountOfBuildsWithTestResults(); assertThat(countOfBuildsWithTestResults, is(1)); - final List testDurationResultSummary = pluggableStorage.getTestDurationResultSummary(); + final List testDurationResultSummary = + pluggableStorage.getTestDurationResultSummary(); assertThat(testDurationResultSummary.get(0).getDuration(), is(200)); - //check storage getSuites method + // check storage getSuites method Collection suiteResults = pluggableStorage.getSuites(); assertThat(suiteResults, hasSize(2)); - //check the two suites name - assertThat(suiteResults, containsInAnyOrder(hasProperty("name", equalTo("supersweet")), hasProperty("name", equalTo("sweet")))); + // check the two suites name + assertThat( + suiteResults, + containsInAnyOrder( + hasProperty("name", equalTo("supersweet")), hasProperty("name", equalTo("sweet")))); - //check one suite detail + // check one suite detail SuiteResult supersweetSuite = suiteResults.stream() .filter(suite -> suite.getName().equals("supersweet")) .findFirst() @@ -256,7 +271,8 @@ public class TestResultStorageJunitTest { } } - @TestExtension public static class Impl extends JunitTestResultStorage { + @TestExtension + public static class Impl extends JunitTestResultStorage { static final String CASE_RESULTS_TABLE = "caseResults"; @@ -264,7 +280,8 @@ public class TestResultStorageJunitTest { private final ConnectionSupplier connectionSupplier = new LocalConnectionSupplier(); - @Override public RemotePublisher createRemotePublisher(Run build) throws IOException { + @Override + public RemotePublisher createRemotePublisher(Run build) throws IOException { try { connectionSupplier.connection(); // make sure we start a local server and create table first } catch (SQLException x) { @@ -280,14 +297,15 @@ public static class DescriptorImpl extends JunitTestResultStorageDescriptor { public String getDisplayName() { return "Test SQL"; } - } @FunctionalInterface private interface Querier { T run(Connection connection) throws SQLException; } - @Override public TestResultImpl load(String job, int build) { + + @Override + public TestResultImpl load(String job, int build) { return new TestResultImpl() { private T query(Querier querier) { if (!queriesPermitted) { @@ -300,9 +318,11 @@ private T query(Querier querier) { throw new RuntimeException(x); } } + private int getCaseCount(String and) { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ?" + and)) { + try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ?" + and)) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { @@ -316,7 +336,10 @@ private int getCaseCount(String and) { private List retrieveCaseResult(String whereCondition) { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT suite, package, testname, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND " + whereCondition)) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT suite, package, testname, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND " + + whereCondition)) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { @@ -338,10 +361,20 @@ private List retrieveCaseResult(String whereCondition) { SuiteResult suiteResult = new SuiteResult(suite, null, null, null); suiteResult.setParent(parent); - CaseResult caseResult = new CaseResult(suiteResult, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace); + CaseResult caseResult = new CaseResult( + suiteResult, + className, + testName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace); ClassResult classResult = classResults.get(className); if (classResult == null) { - classResult = new ClassResult(new PackageResult(new TestResult(this), packageName), className); + classResult = new ClassResult( + new PackageResult(new TestResult(this), packageName), className); } classResult.add(caseResult); caseResult.setClass(classResult); @@ -358,7 +391,9 @@ private List retrieveCaseResult(String whereCondition) { @Override public List getAllPackageResults() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT suite, testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ?")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT suite, testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ?")) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { @@ -380,21 +415,31 @@ public List getAllPackageResults() { SuiteResult suiteResult = new SuiteResult(suite, null, null, null); suiteResult.setParent(parent); - CaseResult caseResult = new CaseResult(suiteResult, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace); + CaseResult caseResult = new CaseResult( + suiteResult, + className, + testName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace); PackageResult packageResult = results.get(packageName); if (packageResult == null) { packageResult = new PackageResult(parent, packageName); } ClassResult classResult = classResults.get(className); if (classResult == null) { - classResult = new ClassResult(new PackageResult(parent, packageName), className); + classResult = + new ClassResult(new PackageResult(parent, packageName), className); } caseResult.setClass(classResult); classResult.add(caseResult); classResults.put(className, classResult); packageResult.add(caseResult); - + results.put(packageName, packageResult); } classResults.values().forEach(ClassResult::tally); @@ -410,7 +455,9 @@ public List getAllPackageResults() { @Override public List getTrendTestResultSummary() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT build, sum(case when errorDetails is not null then 1 else 0 end) as failCount, sum(case when skipped is not null then 1 else 0 end) as skipCount, sum(case when errorDetails is null and skipped is null then 1 else 0 end) as passCount FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? group by build order by build;")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT build, sum(case when errorDetails is not null then 1 else 0 end) as failCount, sum(case when skipped is not null then 1 else 0 end) as skipCount, sum(case when errorDetails is null and skipped is null then 1 else 0 end) as passCount FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? group by build order by build;")) { statement.setString(1, job); try (ResultSet result = statement.executeQuery()) { @@ -422,7 +469,8 @@ public List getTrendTestResultSummary() { int skipped = result.getInt("skipCount"); int total = passed + failed + skipped; - trendTestResultSummaries.add(new TrendTestResultSummary(buildNumber, new TestResultSummary(failed, skipped, passed, total))); + trendTestResultSummaries.add(new TrendTestResultSummary( + buildNumber, new TestResultSummary(failed, skipped, passed, total))); } return trendTestResultSummaries; } @@ -433,7 +481,9 @@ public List getTrendTestResultSummary() { @Override public List getTestDurationResultSummary() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT build, sum(duration) as duration FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? group by build order by build;")) { + try (PreparedStatement statement = + connection.prepareStatement("SELECT build, sum(duration) as duration FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? group by build order by build;")) { statement.setString(1, job); try (ResultSet result = statement.executeQuery()) { @@ -442,7 +492,8 @@ public List getTestDurationResultSummary() { int buildNumber = result.getInt("build"); int duration = result.getInt("duration"); - testDurationResultSummaries.add(new TestDurationResultSummary(buildNumber, duration)); + testDurationResultSummaries.add( + new TestDurationResultSummary(buildNumber, duration)); } return testDurationResultSummaries; } @@ -454,10 +505,10 @@ public List getTestDurationResultSummary() { public List getHistorySummary(int offset) { return query(connection -> { try (PreparedStatement statement = connection.prepareStatement( - "SELECT build, sum(duration) as duration, sum(case when errorDetails is not null then 1 else 0 end) as failCount, sum(case when skipped is not null then 1 else 0 end) as skipCount, sum(case when errorDetails is null and skipped is null then 1 else 0 end) as passCount" + - " FROM " + Impl.CASE_RESULTS_TABLE + - " WHERE job = ? GROUP BY build ORDER BY build DESC LIMIT 25 OFFSET ?;" - )) { + "SELECT build, sum(duration) as duration, sum(case when errorDetails is not null then 1 else 0 end) as failCount, sum(case when skipped is not null then 1 else 0 end) as skipCount, sum(case when errorDetails is null and skipped is null then 1 else 0 end) as passCount" + + " FROM " + + Impl.CASE_RESULTS_TABLE + + " WHERE job = ? GROUP BY build ORDER BY build DESC LIMIT 25 OFFSET ?;")) { statement.setString(1, job); statement.setInt(2, 0); try (ResultSet result = statement.executeQuery()) { @@ -473,7 +524,8 @@ public List getHistorySummary(int offset) { Job theJob = Jenkins.get().getItemByFullName(getJobName(), Job.class); if (theJob != null) { Run run = theJob.getBuildByNumber(buildNumber); - historyTestResultSummaries.add(new HistoryTestResultSummary(run, duration, failed, skipped, passed)); + historyTestResultSummaries.add( + new HistoryTestResultSummary(run, duration, failed, skipped, passed)); } } return historyTestResultSummaries; @@ -485,7 +537,8 @@ public List getHistorySummary(int offset) { @Override public int getCountOfBuildsWithTestResults() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(DISTINCT build) as count FROM caseResults WHERE job = ?;")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT COUNT(DISTINCT build) as count FROM caseResults WHERE job = ?;")) { statement.setString(1, job); try (ResultSet result = statement.executeQuery()) { result.next(); @@ -499,7 +552,9 @@ public int getCountOfBuildsWithTestResults() { @Override public PackageResult getPackageResult(String packageName) { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT suite, testname, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND package = ?")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT suite, testname, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND package = ?")) { statement.setString(1, job); statement.setInt(2, build); statement.setString(3, packageName); @@ -520,8 +575,17 @@ public PackageResult getPackageResult(String packageName) { SuiteResult suiteResult = new SuiteResult(suite, null, null, null); suiteResult.setParent(new TestResult(this)); - CaseResult caseResult = new CaseResult(suiteResult, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace); - + CaseResult caseResult = new CaseResult( + suiteResult, + className, + testName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace); + ClassResult classResult = classResults.get(className); if (classResult == null) { classResult = new ClassResult(packageResult, className); @@ -529,7 +593,7 @@ public PackageResult getPackageResult(String packageName) { classResult.add(caseResult); classResults.put(className, classResult); caseResult.setClass(classResult); - + packageResult.add(caseResult); } classResults.values().forEach(ClassResult::tally); @@ -538,27 +602,23 @@ public PackageResult getPackageResult(String packageName) { } } }); - } - + @Override public Run getFailedSinceRun(CaseResult caseResult) { return query(connection -> { int lastPassingBuildNumber; Job theJob = Objects.requireNonNull(Jenkins.get().getItemByFullName(job, Job.class)); - try (PreparedStatement statement = connection.prepareStatement( - "SELECT build " + - "FROM " + Impl.CASE_RESULTS_TABLE + " " + - "WHERE job = ? " + - "AND build < ? " + - "AND suite = ? " + - "AND package = ? " + - "AND classname = ? " + - "AND testname = ? " + - "AND errordetails IS NULL " + - "ORDER BY BUILD DESC " + - "LIMIT 1" - )) { + try (PreparedStatement statement = connection.prepareStatement("SELECT build " + "FROM " + + Impl.CASE_RESULTS_TABLE + " " + "WHERE job = ? " + + "AND build < ? " + + "AND suite = ? " + + "AND package = ? " + + "AND classname = ? " + + "AND testname = ? " + + "AND errordetails IS NULL " + + "ORDER BY BUILD DESC " + + "LIMIT 1")) { statement.setString(1, job); statement.setInt(2, build); statement.setString(3, caseResult.getSuiteResult().getName()); @@ -570,24 +630,20 @@ public PackageResult getPackageResult(String packageName) { if (!hasPassed) { return theJob.getBuildByNumber(1); } - + lastPassingBuildNumber = result.getInt("build"); } } - try (PreparedStatement statement = connection.prepareStatement( - "SELECT build " + - "FROM " + Impl.CASE_RESULTS_TABLE + " " + - "WHERE job = ? " + - "AND build > ? " + - "AND suite = ? " + - "AND package = ? " + - "AND classname = ? " + - "AND testname = ? " + - "AND errordetails is NOT NULL " + - "ORDER BY BUILD ASC " + - "LIMIT 1" - ) - ) { + try (PreparedStatement statement = connection.prepareStatement("SELECT build " + "FROM " + + Impl.CASE_RESULTS_TABLE + " " + "WHERE job = ? " + + "AND build > ? " + + "AND suite = ? " + + "AND package = ? " + + "AND classname = ? " + + "AND testname = ? " + + "AND errordetails is NOT NULL " + + "ORDER BY BUILD ASC " + + "LIMIT 1")) { statement.setString(1, job); statement.setInt(2, lastPassingBuildNumber); statement.setString(3, caseResult.getSuiteResult().getName()); @@ -603,9 +659,8 @@ public PackageResult getPackageResult(String packageName) { } } }); - } - + @Override public String getJobName() { return job; @@ -623,7 +678,10 @@ public List getFailedTestsByPackage(String packageName) { private List getByPackage(String packageName, String filter) { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT suite, testname, classname, errordetails, duration, skipped, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND package = ? " + filter)) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT suite, testname, classname, errordetails, duration, skipped, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND package = ? " + + filter)) { statement.setString(1, job); statement.setInt(2, build); statement.setString(3, packageName); @@ -643,7 +701,16 @@ private List getByPackage(String packageName, String filter) { SuiteResult suiteResult = new SuiteResult(suite, null, null, null); suiteResult.setParent(new TestResult(this)); - results.add(new CaseResult(suiteResult, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace)); + results.add(new CaseResult( + suiteResult, + className, + testName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace)); } return results; } @@ -651,15 +718,16 @@ private List getByPackage(String packageName, String filter) { }); } - private List getCaseResults(String column) { return retrieveCaseResult(column + " IS NOT NULL"); } - + @Override public SuiteResult getSuite(String name) { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND suite = ?")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? AND suite = ?")) { statement.setString(1, job); statement.setInt(2, build); statement.setString(3, name); @@ -678,7 +746,16 @@ public SuiteResult getSuite(String name) { float duration = result.getFloat("duration"); suiteResult.setParent(parent); - CaseResult caseResult = new CaseResult(suiteResult, className, resultTestName, errorDetails, skipped, duration, stdout, stderr, stacktrace); + CaseResult caseResult = new CaseResult( + suiteResult, + className, + resultTestName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace); final PackageResult packageResult = new PackageResult(parent, packageName); packageResult.add(caseResult); ClassResult classResult = new ClassResult(packageResult, className); @@ -690,19 +767,21 @@ public SuiteResult getSuite(String name) { } } }); - } + @Override public Collection getSuites() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT suite, testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? ORDER BY suite")) { + try (PreparedStatement statement = connection.prepareStatement( + "SELECT suite, testname, package, classname, errordetails, skipped, duration, stdout, stderr, stacktrace FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build = ? ORDER BY suite")) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { SuiteResult suiteResult = null; TestResult parent = new TestResult(this); boolean isFirst = true; - List suites = new ArrayList(); + List suites = new ArrayList(); while (result.next()) { String suiteName = result.getString("suite"); if (isFirst || !suiteResult.getName().equals(suiteName)) { @@ -721,7 +800,16 @@ public Collection getSuites() { float duration = result.getFloat("duration"); suiteResult.setParent(parent); - CaseResult caseResult = new CaseResult(suiteResult, className, resultTestName, errorDetails, skipped, duration, stdout, stderr, stacktrace); + CaseResult caseResult = new CaseResult( + suiteResult, + className, + resultTestName, + errorDetails, + skipped, + duration, + stdout, + stderr, + stacktrace); final PackageResult packageResult = new PackageResult(parent, packageName); packageResult.add(caseResult); ClassResult classResult = new ClassResult(packageResult, className); @@ -733,14 +821,15 @@ public Collection getSuites() { } } }); - }; - - + } + ; @Override public float getTotalTestDuration() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT sum(duration) as duration FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? and build = ?;")) { + try (PreparedStatement statement = + connection.prepareStatement("SELECT sum(duration) as duration FROM " + + Impl.CASE_RESULTS_TABLE + " WHERE job = ? and build = ?;")) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { @@ -753,19 +842,26 @@ public float getTotalTestDuration() { }); } - @Override public int getFailCount() { + @Override + public int getFailCount() { int caseCount = getCaseCount(" AND errorDetails IS NOT NULL"); return caseCount; } - @Override public int getSkipCount() { + + @Override + public int getSkipCount() { int caseCount = getCaseCount(" AND skipped IS NOT NULL"); return caseCount; } - @Override public int getPassCount() { + + @Override + public int getPassCount() { int caseCount = getCaseCount(" AND errorDetails IS NULL AND skipped IS NULL"); return caseCount; } - @Override public int getTotalCount() { + + @Override + public int getTotalCount() { int caseCount = getCaseCount(""); return caseCount; } @@ -802,7 +898,9 @@ public List getPassedTestsByPackage(String packageName) { @CheckForNull public TestResult getPreviousResult() { return query(connection -> { - try (PreparedStatement statement = connection.prepareStatement("SELECT build FROM " + Impl.CASE_RESULTS_TABLE + " WHERE job = ? AND build < ? ORDER BY build DESC LIMIT 1")) { + try (PreparedStatement statement = + connection.prepareStatement("SELECT build FROM " + Impl.CASE_RESULTS_TABLE + + " WHERE job = ? AND build < ? ORDER BY build DESC LIMIT 1")) { statement.setString(1, job); statement.setInt(2, build); try (ResultSet result = statement.executeQuery()) { @@ -819,7 +917,7 @@ public TestResult getPreviousResult() { } @NonNull - @Override + @Override public TestResult getResultByNodes(@NonNull List nodeIds) { return new TestResult(this); // TODO } @@ -830,7 +928,8 @@ private static class RemotePublisherImpl implements RemotePublisher { private final String job; private final int build; - // TODO keep the same supplier and thus Connection open across builds, so long as the database config remains unchanged + // TODO keep the same supplier and thus Connection open across builds, so long as the database config + // remains unchanged private final ConnectionSupplier connectionSupplier; RemotePublisherImpl(String job, int build) { @@ -839,10 +938,13 @@ private static class RemotePublisherImpl implements RemotePublisher { connectionSupplier = new RemoteConnectionSupplier(); } - @Override public void publish(TestResult result, TaskListener listener) throws IOException { + @Override + public void publish(TestResult result, TaskListener listener) throws IOException { try { Connection connection = connectionSupplier.connection(); - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + CASE_RESULTS_TABLE + " (job, build, suite, package, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { + try (PreparedStatement statement = connection.prepareStatement( + "INSERT INTO " + CASE_RESULTS_TABLE + + " (job, build, suite, package, className, testName, errorDetails, skipped, duration, stdout, stderr, stacktrace) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { int count = 0; for (SuiteResult suiteResult : result.getSuites()) { for (CaseResult caseResult : suiteResult.getCases()) { @@ -864,17 +966,20 @@ private static class RemotePublisherImpl implements RemotePublisher { statement.setNull(8, Types.VARCHAR); } statement.setFloat(9, caseResult.getDuration()); - if (caseResult.getStdout() != null && !caseResult.getStdout().isEmpty()) { + if (caseResult.getStdout() != null + && !caseResult.getStdout().isEmpty()) { statement.setString(10, caseResult.getStdout()); } else { statement.setNull(10, Types.VARCHAR); } - if (caseResult.getStderr() != null && !caseResult.getStderr().isEmpty()) { + if (caseResult.getStderr() != null + && !caseResult.getStderr().isEmpty()) { statement.setString(11, caseResult.getStderr()); } else { statement.setNull(11, Types.VARCHAR); } - if (caseResult.getErrorStackTrace() != null && !caseResult.getErrorStackTrace().isEmpty()) { + if (caseResult.getErrorStackTrace() != null + && !caseResult.getErrorStackTrace().isEmpty()) { statement.setString(12, caseResult.getErrorStackTrace()); } else { statement.setNull(12, Types.VARCHAR); @@ -889,10 +994,9 @@ private static class RemotePublisherImpl implements RemotePublisher { throw new IOException(x); } } - } - static abstract class ConnectionSupplier { // TODO AutoCloseable + abstract static class ConnectionSupplier { // TODO AutoCloseable private transient Connection connection; @@ -908,18 +1012,20 @@ synchronized Connection connection() throws SQLException { } return connection; } - } static class LocalConnectionSupplier extends ConnectionSupplier { - @Override protected Database database() { + @Override + protected Database database() { return GlobalDatabaseConfiguration.get().getDatabase(); } - @Override protected void initialize(Connection connection) throws SQLException { + @Override + protected void initialize(Connection connection) throws SQLException { boolean exists = false; - try (ResultSet rs = connection.getMetaData().getTables(null, null, CASE_RESULTS_TABLE, new String[] {"TABLE"})) { + try (ResultSet rs = + connection.getMetaData().getTables(null, null, CASE_RESULTS_TABLE, new String[] {"TABLE"})) { while (rs.next()) { if (rs.getString("TABLE_NAME").equalsIgnoreCase(CASE_RESULTS_TABLE)) { exists = true; @@ -930,11 +1036,12 @@ static class LocalConnectionSupplier extends ConnectionSupplier { if (!exists) { try (Statement statement = connection.createStatement()) { // TODO this and joined tables: nodeId, enclosingBlocks, enclosingBlockNames, etc. - statement.execute("CREATE TABLE " + CASE_RESULTS_TABLE + "(job varchar(255), build int, suite varchar(255), package varchar(255), className varchar(255), testName varchar(255), errorDetails varchar(255), skipped varchar(255), duration numeric, stdout varchar(100000), stderr varchar(100000), stacktrace varchar(100000))"); + statement.execute( + "CREATE TABLE " + CASE_RESULTS_TABLE + + "(job varchar(255), build int, suite varchar(255), package varchar(255), className varchar(255), testName varchar(255), errorDetails varchar(255), skipped varchar(255), duration numeric, stdout varchar(100000), stderr varchar(100000), stacktrace varchar(100000))"); } } } - } /** @@ -953,12 +1060,11 @@ static class RemoteConnectionSupplier extends ConnectionSupplier implements Seri databaseXml = XSTREAM.toXML(GlobalDatabaseConfiguration.get().getDatabase()); } - @Override protected Database database() { + @Override + protected Database database() { return (Database) XSTREAM.fromXML(databaseXml); } - } - } // https://gist.github.com/mikbuch/299568988fa7997cb28c7c84309232b1 @@ -984,5 +1090,4 @@ private static void printResultSet(ResultSet rs) throws SQLException { } LOGGER.log(Level.INFO, sb.toString()); } - } diff --git a/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/BenchmarkRunner.java b/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/BenchmarkRunner.java index 19e7cbbe..36b3a40a 100644 --- a/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/BenchmarkRunner.java +++ b/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/BenchmarkRunner.java @@ -12,10 +12,10 @@ public class BenchmarkRunner { @Test public void runJmhBenchmarks() throws Exception { ChainedOptionsBuilder options = new OptionsBuilder() - .mode(Mode.AverageTime) - .forks(2) - .resultFormat(ResultFormatType.JSON) - .result("jmh-report.json"); + .mode(Mode.AverageTime) + .forks(2) + .resultFormat(ResultFormatType.JSON) + .result("jmh-report.json"); // Automatically detect benchmark classes annotated with @JmhBenchmark new BenchmarkFinder(getClass()).findBenchmarks(options); diff --git a/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/TrendGraphBenchmark.java b/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/TrendGraphBenchmark.java index e5036e08..84338dcc 100644 --- a/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/TrendGraphBenchmark.java +++ b/src/test/java/io/jenkins/plugins/junit/storage/benchmarks/TrendGraphBenchmark.java @@ -23,20 +23,20 @@ public static class JenkinsState extends JmhBenchmarkState { WorkflowJob lastJob; - public static final String SIMPLE_TEST_RESULT = "node {\n" + - " writeFile file: 'x.xml', text: '''" + - "" + - "" + - "" + - "'''\n" + - " def s = junit 'x.xml'\n" + - " echo(/summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + - " writeFile file: 'x.xml', text: '''" + - "" + - "'''\n" + - " s = junit 'x.xml'\n" + - " echo(/next summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + - "}"; + public static final String SIMPLE_TEST_RESULT = + "node {\n" + " writeFile file: 'x.xml', text: '''" + + "" + + "" + + "" + + "'''\n" + + " def s = junit 'x.xml'\n" + + " echo(/summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + + " writeFile file: 'x.xml', text: '''" + + "" + + "'''\n" + + " s = junit 'x.xml'\n" + + " echo(/next summary: fail=$s.failCount skip=$s.skipCount pass=$s.passCount total=$s.totalCount/)\n" + + "}"; @Override public void setup() throws Exception { @@ -45,15 +45,15 @@ public void setup() throws Exception { createLotsOfRuns("b", 1000); createLotsOfRuns("c", 1000); createLotsOfRuns("d", 1000); - + System.out.println("Next build number: " + lastJob.getNextBuildNumber()); } - private void createLotsOfRuns(String jobName, int runCount) throws java.io.IOException, InterruptedException, ExecutionException { + private void createLotsOfRuns(String jobName, int runCount) + throws java.io.IOException, InterruptedException, ExecutionException { Jenkins jenkins = Jenkins.get(); lastJob = jenkins.createProject(WorkflowJob.class, jobName); - lastJob.setDefinition(new CpsFlowDefinition( - SIMPLE_TEST_RESULT, true)); + lastJob.setDefinition(new CpsFlowDefinition(SIMPLE_TEST_RESULT, true)); List> queueTaskFutures = new java.util.ArrayList<>(runCount); for (int i = 0; i < runCount; i++) { QueueTaskFuture e = lastJob.scheduleBuild2(0); @@ -72,9 +72,8 @@ private void createLotsOfRuns(String jobName, int runCount) throws java.io.IOExc } }); } - } - + @Benchmark public void benchmark(JenkinsState cascState, Blackhole blackhole) { TestResultProjectAction action = cascState.lastJob.getAction(TestResultProjectAction.class);