mirror of https://github.com/jenkinsci/jenkins.git
[FIXED JENKINS-23263] JUnit reporter moved to a plugin.
This commit is contained in:
parent
ec22212b78
commit
16197ea502
|
@ -55,7 +55,9 @@ Upcoming changes</a>
|
|||
<!-- Record your changes in the trunk here. -->
|
||||
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
|
||||
<ul class=image>
|
||||
<li class=>
|
||||
<li class="major rfe">
|
||||
Moved JUnit reporting functionality to a plugin.
|
||||
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-23263">issue 23263</a>)
|
||||
</ul>
|
||||
</div><!--=TRUNK-END=-->
|
||||
|
||||
|
|
|
@ -298,7 +298,8 @@ public class ClassicPluginStrategy implements PluginStrategy {
|
|||
new DetachedPlugin("matrix-auth","1.535.*","1.0.2"),
|
||||
new DetachedPlugin("windows-slaves","1.547.*","1.0"),
|
||||
new DetachedPlugin("antisamy-markup-formatter","1.553.*","1.0"),
|
||||
new DetachedPlugin("matrix-project","1.561.*","1.0")
|
||||
new DetachedPlugin("matrix-project","1.561.*","1.0"),
|
||||
new DetachedPlugin("junit","1.577.*","1.0")
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,8 +54,6 @@ import hudson.tasks.BuildWrapper;
|
|||
import hudson.tasks.Builder;
|
||||
import hudson.tasks.Fingerprinter.FingerprintAction;
|
||||
import hudson.tasks.Publisher;
|
||||
import hudson.tasks.test.AbstractTestResultAction;
|
||||
import hudson.tasks.test.AggregatedTestResultAction;
|
||||
import hudson.util.*;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.kohsuke.stapler.HttpResponse;
|
||||
|
@ -1041,15 +1039,23 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
|
|||
/**
|
||||
* @deprecated Use {@link #getAction(Class)} on {@link AbstractTestResultAction}.
|
||||
*/
|
||||
public AbstractTestResultAction getTestResultAction() {
|
||||
return getAction(AbstractTestResultAction.class);
|
||||
public Action getTestResultAction() {
|
||||
try {
|
||||
return getAction(Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.tasks.test.AbstractTestResultAction").asSubclass(Action.class));
|
||||
} catch (ClassNotFoundException x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getAction(Class)} on {@link AggregatedTestResultAction}.
|
||||
*/
|
||||
public AggregatedTestResultAction getAggregatedTestResultAction() {
|
||||
return getAction(AggregatedTestResultAction.class);
|
||||
public Action getAggregatedTestResultAction() {
|
||||
try {
|
||||
return getAction(Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.tasks.test.AggregatedTestResultAction").asSubclass(Action.class));
|
||||
} catch (ClassNotFoundException x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
package hudson.model;
|
||||
|
||||
import hudson.Functions;
|
||||
import hudson.tasks.test.TestResultProjectAction;
|
||||
|
||||
/**
|
||||
* Object that contributes additional information, behaviors, and UIs to {@link ModelObject}
|
||||
|
@ -46,7 +45,7 @@ import hudson.tasks.test.TestResultProjectAction;
|
|||
* it will be displayed as a floating box on the top page of
|
||||
* the target {@link ModelObject}. (For example, this is how
|
||||
* the JUnit test result trend shows up in the project top page.
|
||||
* See {@link TestResultProjectAction}.)
|
||||
* See {@code TestResultProjectAction}.)
|
||||
*
|
||||
* <p>
|
||||
* On the target {@link ModelObject} page, actions are rendered as an item in the side panel
|
||||
|
|
|
@ -26,7 +26,6 @@ package hudson.model;
|
|||
import hudson.tasks.BuildStep;
|
||||
import hudson.tasks.Recorder;
|
||||
import hudson.tasks.Builder;
|
||||
import hudson.tasks.junit.JUnitResultArchiver;
|
||||
import hudson.scm.SCM;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
|
@ -57,7 +56,7 @@ import javax.annotation.Nonnull;
|
|||
*
|
||||
* <h2>Example</h2>
|
||||
* <p>
|
||||
* {@link JUnitResultArchiver} provides a good example of how a {@link Recorder} can
|
||||
* {@code JUnitResultArchiver} provides a good example of how a {@link Recorder} can
|
||||
* depend on its earlier result.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
|
@ -127,9 +126,9 @@ public final class CheckPoint {
|
|||
*
|
||||
* <ol>
|
||||
* <li>Build #1, #2, and #3 happens around the same time
|
||||
* <li>Build #3 waits for check point {@link JUnitResultArchiver}
|
||||
* <li>Build #3 waits for check point {@code JUnitResultArchiver}
|
||||
* <li>Build #2 aborts before getting to that check point
|
||||
* <li>Build #1 finally checks in {@link JUnitResultArchiver}
|
||||
* <li>Build #1 finally checks in {@code JUnitResultArchiver}
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
|
|
|
@ -1,670 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.util.TextFile;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.jvnet.localizer.Localizable;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Run;
|
||||
import hudson.tasks.test.TestResult;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* One test result.
|
||||
*
|
||||
* Non-final since 1.526
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class CaseResult extends TestResult implements Comparable<CaseResult> {
|
||||
private static final Logger LOGGER = Logger.getLogger(CaseResult.class.getName());
|
||||
private final float duration;
|
||||
/**
|
||||
* In JUnit, a test is a method of a class. This field holds the fully qualified class name
|
||||
* that the test was in.
|
||||
*/
|
||||
private final String className;
|
||||
/**
|
||||
* This field retains the method name.
|
||||
*/
|
||||
private final String testName;
|
||||
private transient String safeName;
|
||||
private final boolean skipped;
|
||||
private final String skippedMessage;
|
||||
private final String errorStackTrace;
|
||||
private final String errorDetails;
|
||||
private transient SuiteResult parent;
|
||||
|
||||
private transient ClassResult classResult;
|
||||
|
||||
/**
|
||||
* Some tools report stdout and stderr at testcase level (such as Maven surefire plugin), others do so at
|
||||
* the suite level (such as Ant JUnit task.)
|
||||
*
|
||||
* If these information are reported at the test case level, these fields are set,
|
||||
* otherwise null, in which case {@link SuiteResult#stdout}.
|
||||
*/
|
||||
private final String stdout,stderr;
|
||||
|
||||
/**
|
||||
* This test has been failing since this build number (not id.)
|
||||
*
|
||||
* If {@link #isPassed() passing}, this field is left unused to 0.
|
||||
*/
|
||||
private /*final*/ int failedSince;
|
||||
|
||||
private static float parseTime(Element testCase) {
|
||||
String time = testCase.attributeValue("time");
|
||||
if(time!=null) {
|
||||
time = time.replace(",","");
|
||||
try {
|
||||
return Float.parseFloat(time);
|
||||
} catch (NumberFormatException e) {
|
||||
try {
|
||||
return new DecimalFormat().parse(time).floatValue();
|
||||
} catch (ParseException x) {
|
||||
// hmm, don't know what this format is.
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
CaseResult(SuiteResult parent, Element testCase, String testClassName, boolean keepLongStdio) {
|
||||
// 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)
|
||||
// // 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.
|
||||
*/
|
||||
String nameAttr = testCase.attributeValue("name");
|
||||
if(testClassName==null && nameAttr.contains(".")) {
|
||||
testClassName = nameAttr.substring(0,nameAttr.lastIndexOf('.'));
|
||||
nameAttr = nameAttr.substring(nameAttr.lastIndexOf('.')+1);
|
||||
}
|
||||
|
||||
className = testClassName;
|
||||
testName = nameAttr;
|
||||
errorStackTrace = getError(testCase);
|
||||
errorDetails = getErrorMessage(testCase);
|
||||
this.parent = parent;
|
||||
duration = parseTime(testCase);
|
||||
skipped = isMarkedAsSkipped(testCase);
|
||||
skippedMessage = getSkippedMessage(testCase);
|
||||
@SuppressWarnings("LeakingThisInConstructor")
|
||||
Collection<CaseResult> _this = Collections.singleton(this);
|
||||
stdout = possiblyTrimStdio(_this, keepLongStdio, testCase.elementText("system-out"));
|
||||
stderr = possiblyTrimStdio(_this, keepLongStdio, testCase.elementText("system-err"));
|
||||
}
|
||||
|
||||
private static final int HALF_MAX_SIZE = 500;
|
||||
static String possiblyTrimStdio(Collection<CaseResult> results, boolean keepLongStdio, String stdio) { // HUDSON-6516
|
||||
if (stdio == null) {
|
||||
return null;
|
||||
}
|
||||
if (!isTrimming(results, keepLongStdio)) {
|
||||
return stdio;
|
||||
}
|
||||
int len = stdio.length();
|
||||
int middle = len - HALF_MAX_SIZE * 2;
|
||||
if (middle <= 0) {
|
||||
return stdio;
|
||||
}
|
||||
return stdio.subSequence(0, HALF_MAX_SIZE) + "\n...[truncated " + middle + " chars]...\n" + stdio.subSequence(len - HALF_MAX_SIZE, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flavor of {@link #possiblyTrimStdio(Collection, boolean, String)} that doesn't try to read the whole thing into memory.
|
||||
*/
|
||||
static String possiblyTrimStdio(Collection<CaseResult> results, boolean keepLongStdio, File stdio) throws IOException {
|
||||
if (!isTrimming(results, keepLongStdio) && stdio.length()<1024*1024) {
|
||||
return FileUtils.readFileToString(stdio);
|
||||
}
|
||||
|
||||
long len = stdio.length();
|
||||
long middle = len - HALF_MAX_SIZE * 2;
|
||||
if (middle <= 0) {
|
||||
return FileUtils.readFileToString(stdio);
|
||||
}
|
||||
|
||||
TextFile tx = new TextFile(stdio);
|
||||
String head = tx.head(HALF_MAX_SIZE);
|
||||
String tail = tx.fastTail(HALF_MAX_SIZE);
|
||||
|
||||
int headBytes = head.getBytes().length;
|
||||
int tailBytes = tail.getBytes().length;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return head + "\n...[truncated " + middle + " bytes]...\n" + tail;
|
||||
}
|
||||
|
||||
private static boolean isTrimming(Collection<CaseResult> results, boolean keepLongStdio) {
|
||||
if (keepLongStdio) return false;
|
||||
for (CaseResult result : results) {
|
||||
// if there's a failure, do not trim and keep the whole thing
|
||||
if (result.errorStackTrace != null)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used to create a fake failure, when Hudson fails to load data from XML files.
|
||||
*
|
||||
* Public since 1.526.
|
||||
*/
|
||||
public CaseResult(SuiteResult parent, String testName, String errorStackTrace) {
|
||||
this.className = parent == null ? "unnamed" : parent.getName();
|
||||
this.testName = testName;
|
||||
this.errorStackTrace = errorStackTrace;
|
||||
this.errorDetails = "";
|
||||
this.parent = parent;
|
||||
this.stdout = null;
|
||||
this.stderr = null;
|
||||
this.duration = 0.0f;
|
||||
this.skipped = false;
|
||||
this.skippedMessage = null;
|
||||
}
|
||||
|
||||
public ClassResult getParent() {
|
||||
return classResult;
|
||||
}
|
||||
|
||||
private static String getError(Element testCase) {
|
||||
String msg = testCase.elementText("error");
|
||||
if(msg!=null)
|
||||
return msg;
|
||||
return testCase.elementText("failure");
|
||||
}
|
||||
|
||||
private static String getErrorMessage(Element testCase) {
|
||||
|
||||
Element msg = testCase.element("error");
|
||||
if (msg == null) {
|
||||
msg = testCase.element("failure");
|
||||
}
|
||||
if (msg == null) {
|
||||
return null; // no error or failure elements! damn!
|
||||
}
|
||||
|
||||
return msg.attributeValue("message");
|
||||
}
|
||||
|
||||
/**
|
||||
* If the testCase element includes the skipped element (as output by TestNG), then
|
||||
* the test has neither passed nor failed, it was never run.
|
||||
*/
|
||||
private static boolean isMarkedAsSkipped(Element testCase) {
|
||||
return testCase.element("skipped") != null;
|
||||
}
|
||||
|
||||
private static String getSkippedMessage(Element testCase) {
|
||||
String message = null;
|
||||
Element skippedElement = testCase.element("skipped");
|
||||
|
||||
if (skippedElement != null) {
|
||||
message = skippedElement.attributeValue("message");
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return TestNameTransformer.getTransformedName(testName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the test, which is returned from {@code TestCase.getName()}
|
||||
*
|
||||
* <p>
|
||||
* Note that this may contain any URL-unfriendly character.
|
||||
*/
|
||||
@Exported(visibility=999)
|
||||
public @Override String getName() {
|
||||
return testName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the human readable title of this result object.
|
||||
*/
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Case Result: " + getDisplayName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration of the test, in seconds
|
||||
*/
|
||||
@Exported(visibility=9)
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of {@link #getName()} that's URL-safe.
|
||||
*/
|
||||
public @Override synchronized String getSafeName() {
|
||||
if (safeName != null) {
|
||||
return safeName;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(testName);
|
||||
for( int i=0; i<buf.length(); i++ ) {
|
||||
char ch = buf.charAt(i);
|
||||
if(!Character.isJavaIdentifierPart(ch))
|
||||
buf.setCharAt(i,'_');
|
||||
}
|
||||
Collection<CaseResult> siblings = (classResult ==null ? Collections.<CaseResult>emptyList(): classResult.getChildren());
|
||||
return safeName = uniquifyName(siblings, buf.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name of a test class.
|
||||
*/
|
||||
@Exported(visibility=9)
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the simple (not qualified) class name.
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
int idx = className.lastIndexOf('.');
|
||||
return className.substring(idx+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the package name of a test case
|
||||
*/
|
||||
public String getPackageName() {
|
||||
int idx = className.lastIndexOf('.');
|
||||
if(idx<0) return "(root)";
|
||||
else return className.substring(0,idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return className+'.'+getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.515
|
||||
*/
|
||||
public String getFullDisplayName() {
|
||||
return TestNameTransformer.getTransformedName(getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFailCount() {
|
||||
if (isFailed()) return 1; else return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
if (isSkipped()) return 1; else return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPassCount() {
|
||||
return isPassed() ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this test failed, then return the build number
|
||||
* when this test started failing.
|
||||
*/
|
||||
@Exported(visibility=9)
|
||||
public int getFailedSince() {
|
||||
// If we haven't calculated failedSince yet, and we should,
|
||||
// do it now.
|
||||
if (failedSince==0 && getFailCount()==1) {
|
||||
CaseResult prev = getPreviousResult();
|
||||
if(prev!=null && !prev.isPassed())
|
||||
this.failedSince = prev.getFailedSince();
|
||||
else if (getOwner() != null) {
|
||||
this.failedSince = getOwner().getNumber();
|
||||
} else {
|
||||
LOGGER.warning("trouble calculating getFailedSince. We've got prev, but no owner.");
|
||||
// failedSince will be 0, which isn't correct.
|
||||
}
|
||||
}
|
||||
return failedSince;
|
||||
}
|
||||
|
||||
public Run<?,?> getFailedSinceRun() {
|
||||
return getOwner().getParent().getBuildByNumber(getFailedSince());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of consecutive builds (including this)
|
||||
* that this test case has been failing.
|
||||
*/
|
||||
@Exported(visibility=9)
|
||||
public int getAge() {
|
||||
if(isPassed())
|
||||
return 0;
|
||||
else if (getOwner() != null) {
|
||||
return getOwner().getNumber()-getFailedSince()+1;
|
||||
} else {
|
||||
LOGGER.fine("Trying to get age of a CaseResult without an owner");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The stdout of this test.
|
||||
*
|
||||
* <p>
|
||||
* Depending on the tool that produced the XML report, this method works somewhat inconsistently.
|
||||
* With some tools (such as Maven surefire plugin), you get the accurate information, that is
|
||||
* the stdout from this test case. With some other tools (such as the JUnit task in Ant), this
|
||||
* method returns the stdout produced by the entire test suite.
|
||||
*
|
||||
* <p>
|
||||
* If you need to know which is the case, compare this output from {@link SuiteResult#getStdout()}.
|
||||
* @since 1.294
|
||||
*/
|
||||
@Exported
|
||||
public String getStdout() {
|
||||
if(stdout!=null) return stdout;
|
||||
SuiteResult sr = getSuiteResult();
|
||||
if (sr==null) return "";
|
||||
return getSuiteResult().getStdout();
|
||||
}
|
||||
|
||||
/**
|
||||
* The stderr of this test.
|
||||
*
|
||||
* @see #getStdout()
|
||||
* @since 1.294
|
||||
*/
|
||||
@Exported
|
||||
public String getStderr() {
|
||||
if(stderr!=null) return stderr;
|
||||
SuiteResult sr = getSuiteResult();
|
||||
if (sr==null) return "";
|
||||
return getSuiteResult().getStderr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaseResult getPreviousResult() {
|
||||
if (parent == null) return null;
|
||||
SuiteResult pr = parent.getPreviousResult();
|
||||
if(pr==null) return null;
|
||||
return pr.getCase(getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Case results have no children
|
||||
* @return null
|
||||
*/
|
||||
@Override
|
||||
public TestResult findCorrespondingResult(String id) {
|
||||
if (id.equals(safe(getName()))) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that failed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getFailedTests() {
|
||||
return singletonListOfThisOrEmptyList(isFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that passed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getPassedTests() {
|
||||
return singletonListOfThisOrEmptyList(isPassed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that were skipped
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty list
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getSkippedTests() {
|
||||
return singletonListOfThisOrEmptyList(isSkipped());
|
||||
}
|
||||
|
||||
private Collection<? extends hudson.tasks.test.TestResult> singletonListOfThisOrEmptyList(boolean f) {
|
||||
if (f)
|
||||
return singletonList(this);
|
||||
else
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the stack trace, or otherwise null.
|
||||
*/
|
||||
@Exported
|
||||
public String getErrorStackTrace() {
|
||||
return errorStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the text from the message.
|
||||
*/
|
||||
@Exported
|
||||
public String getErrorDetails() {
|
||||
return errorDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the test was not skipped and did not fail, false otherwise.
|
||||
*/
|
||||
public boolean isPassed() {
|
||||
return !skipped && errorStackTrace==null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the test was skipped or not. TestNG allows tests to be
|
||||
* skipped if their dependencies fail or they are part of a group that has
|
||||
* been configured to be skipped.
|
||||
* @return true if the test was not executed, false otherwise.
|
||||
*/
|
||||
@Exported(visibility=9)
|
||||
public boolean isSkipped() {
|
||||
return skipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the test was not skipped and did not pass, false otherwise.
|
||||
* @since 1.520
|
||||
*/
|
||||
public boolean isFailed() {
|
||||
return !isPassed() && !isSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the reason given for the test being being skipped.
|
||||
* @return the message given for a skipped test if one has been provided, null otherwise.
|
||||
* @since 1.507
|
||||
*/
|
||||
@Exported
|
||||
public String getSkippedMessage() {
|
||||
return skippedMessage;
|
||||
}
|
||||
|
||||
public SuiteResult getSuiteResult() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractBuild<?,?> getOwner() {
|
||||
SuiteResult sr = getSuiteResult();
|
||||
if (sr==null) {
|
||||
LOGGER.warning("In getOwner(), getSuiteResult is null"); return null; }
|
||||
hudson.tasks.junit.TestResult tr = sr.getParent();
|
||||
if (tr==null) {
|
||||
LOGGER.warning("In getOwner(), suiteResult.getParent() is null."); return null; }
|
||||
return tr.getOwner();
|
||||
}
|
||||
|
||||
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.
|
||||
if(!isPassed() && failedSince==0) {
|
||||
CaseResult prev = getPreviousResult();
|
||||
if(prev!=null && !prev.isPassed())
|
||||
this.failedSince = prev.failedSince;
|
||||
else
|
||||
this.failedSince = getOwner().getNumber();
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(CaseResult that) {
|
||||
return this.getFullName().compareTo(that.getFullName());
|
||||
}
|
||||
|
||||
@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) {
|
||||
return isPassed() ? Status.PASSED : Status.FAILED;
|
||||
}
|
||||
|
||||
if(pr.isPassed()) {
|
||||
return isPassed() ? Status.PASSED : Status.REGRESSION;
|
||||
} else {
|
||||
return isPassed() ? Status.FIXED : Status.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void setClass(ClassResult classResult) {
|
||||
this.classResult = classResult;
|
||||
}
|
||||
|
||||
void replaceParent(SuiteResult parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants that represent the status of this test.
|
||||
*/
|
||||
public enum Status {
|
||||
/**
|
||||
* This test runs OK, just like its previous run.
|
||||
*/
|
||||
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),
|
||||
/**
|
||||
* This test failed, just like its previous run.
|
||||
*/
|
||||
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),
|
||||
/**
|
||||
* This test has been running OK, but now it failed.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public String getCssClass() {
|
||||
return cssClass;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
public boolean isRegression() {
|
||||
return this==REGRESSION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For sorting errors by age.
|
||||
*/
|
||||
/*package*/ static final Comparator<CaseResult> BY_AGE = new Comparator<CaseResult>() {
|
||||
public int compare(CaseResult lhs, CaseResult rhs) {
|
||||
return lhs.getAge()-rhs.getAge();
|
||||
}
|
||||
};
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.tasks.test.TabulatedResult;
|
||||
import hudson.tasks.test.TestResult;
|
||||
import hudson.tasks.test.TestObject;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Cumulative test result of a test class.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public final class ClassResult extends TabulatedResult implements Comparable<ClassResult> {
|
||||
private final String className; // simple name
|
||||
private transient String safeName;
|
||||
|
||||
private final List<CaseResult> cases = new ArrayList<CaseResult>();
|
||||
|
||||
private int passCount,failCount,skipCount;
|
||||
|
||||
private float duration;
|
||||
|
||||
private final PackageResult parent;
|
||||
|
||||
ClassResult(PackageResult parent, String className) {
|
||||
this.parent = parent;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractBuild<?, ?> getOwner() {
|
||||
return (parent==null ? null: parent.getOwner());
|
||||
}
|
||||
|
||||
public PackageResult getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassResult getPreviousResult() {
|
||||
if(parent==null) return null;
|
||||
TestResult pr = parent.getPreviousResult();
|
||||
if(pr==null) return null;
|
||||
if(pr instanceof PackageResult) {
|
||||
return ((PackageResult)pr).getClassResult(getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public hudson.tasks.test.TestResult findCorrespondingResult(String id) {
|
||||
String myID = safe(getName());
|
||||
String caseName = id;
|
||||
int base = id.indexOf(myID);
|
||||
if (base > 0) {
|
||||
int caseNameStart = base + myID.length() + 1;
|
||||
if (id.length() > caseNameStart) {
|
||||
caseName = id.substring(caseNameStart);
|
||||
}
|
||||
}
|
||||
CaseResult child = getCaseResult(caseName);
|
||||
if (child != null) {
|
||||
return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return Messages.ClassResult_getTitle(getDisplayName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChildTitle() {
|
||||
return "Class Reults";
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
public String getName() {
|
||||
int idx = className.lastIndexOf('.');
|
||||
if(idx<0) return className;
|
||||
else return className.substring(idx+1);
|
||||
}
|
||||
|
||||
public @Override synchronized String getSafeName() {
|
||||
if (safeName != null) {
|
||||
return safeName;
|
||||
}
|
||||
return safeName = uniquifyName(parent.getChildren(), safe(getName()));
|
||||
}
|
||||
|
||||
public CaseResult getCaseResult(String name) {
|
||||
for (CaseResult c : cases) {
|
||||
if(c.getSafeName().equals(name))
|
||||
return c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDynamic(String name, StaplerRequest req, StaplerResponse rsp) {
|
||||
CaseResult c = getCaseResult(name);
|
||||
if (c != null) {
|
||||
return c;
|
||||
} else {
|
||||
return super.getDynamic(name, req, rsp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Exported(name="child")
|
||||
public List<CaseResult> getChildren() {
|
||||
return cases;
|
||||
}
|
||||
|
||||
public boolean hasChildren() {
|
||||
return ((cases != null) && (cases.size() > 0));
|
||||
}
|
||||
|
||||
// TODO: wait for stapler 1.60 @Exported
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Exported
|
||||
public int getPassCount() {
|
||||
return passCount;
|
||||
}
|
||||
|
||||
@Exported
|
||||
public int getFailCount() {
|
||||
return failCount;
|
||||
}
|
||||
|
||||
@Exported
|
||||
public int getSkipCount() {
|
||||
return skipCount;
|
||||
}
|
||||
|
||||
public void add(CaseResult r) {
|
||||
cases.add(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recount my children.
|
||||
*/
|
||||
@Override
|
||||
public void tally() {
|
||||
passCount=failCount=skipCount=0;
|
||||
duration=0;
|
||||
for (CaseResult r : cases) {
|
||||
r.setClass(this);
|
||||
if (r.isSkipped()) {
|
||||
skipCount++;
|
||||
}
|
||||
else if(r.isPassed()) {
|
||||
passCount++;
|
||||
}
|
||||
else {
|
||||
failCount++;
|
||||
}
|
||||
duration += r.getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void freeze() {
|
||||
passCount=failCount=skipCount=0;
|
||||
duration=0;
|
||||
for (CaseResult r : cases) {
|
||||
r.setClass(this);
|
||||
if (r.isSkipped()) {
|
||||
skipCount++;
|
||||
}
|
||||
else if(r.isPassed()) {
|
||||
passCount++;
|
||||
}
|
||||
else {
|
||||
failCount++;
|
||||
}
|
||||
duration += r.getDuration();
|
||||
}
|
||||
Collections.sort(cases);
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public int compareTo(ClassResult that) {
|
||||
return this.className.compareTo(that.className);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return TestNameTransformer.getTransformedName(getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.515
|
||||
*/
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return getParent().getName() + "." + className;
|
||||
}
|
||||
|
||||
public String getFullDisplayName() {
|
||||
return getParent().getDisplayName() + "." + TestNameTransformer.getTransformedName(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path to this test case from the given object.
|
||||
*/
|
||||
@Override
|
||||
public String getRelativePathFrom(TestObject it) {
|
||||
if(it instanceof CaseResult) {
|
||||
return "..";
|
||||
} else {
|
||||
return super.getRelativePathFrom(it);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Tom Huybrechts, Yahoo!, Inc., Seiji Sogabe
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import jenkins.model.Jenkins;
|
||||
import hudson.tasks.test.TestObject;
|
||||
import hudson.tasks.test.TestResult;
|
||||
import hudson.util.ChartUtil;
|
||||
import hudson.util.ColorPalette;
|
||||
import hudson.util.DataSetBuilder;
|
||||
import hudson.util.Graph;
|
||||
import hudson.util.ShiftedCategoryAxis;
|
||||
import hudson.util.StackedAreaRenderer2;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.CategoryAxis;
|
||||
import org.jfree.chart.axis.CategoryLabelPositions;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.CategoryPlot;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.renderer.category.StackedAreaRenderer;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
import org.kohsuke.stapler.Stapler;
|
||||
|
||||
/**
|
||||
* History of {@link hudson.tasks.test.TestObject} over time.
|
||||
*
|
||||
* @since 1.320
|
||||
*/
|
||||
public class History {
|
||||
private final TestObject testObject;
|
||||
|
||||
public History(TestObject testObject) {
|
||||
this.testObject = testObject;
|
||||
}
|
||||
|
||||
public TestObject getTestObject() {
|
||||
return testObject;
|
||||
}
|
||||
|
||||
public boolean historyAvailable() {
|
||||
if (testObject.getOwner().getParent().getBuilds().size() > 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<TestResult> getList(int start, int end) {
|
||||
List<TestResult> list = new ArrayList<TestResult>();
|
||||
end = Math.min(end, testObject.getOwner().getParent().getBuilds().size());
|
||||
for (AbstractBuild<?,?> b: testObject.getOwner().getParent().getBuilds().subList(start, end)) {
|
||||
if (b.isBuilding()) continue;
|
||||
TestResult o = testObject.getResultInBuild(b);
|
||||
if (o != null) {
|
||||
list.add(o);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<TestResult> getList() {
|
||||
return getList(0, testObject.getOwner().getParent().getBuilds().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Graph of duration of tests over time.
|
||||
*/
|
||||
public Graph getDurationGraph() {
|
||||
return new GraphImpl("seconds") {
|
||||
|
||||
protected DataSetBuilder<String, ChartLabel> createDataSet() {
|
||||
DataSetBuilder<String, ChartLabel> data = new DataSetBuilder<String, ChartLabel>();
|
||||
|
||||
List<TestResult> list;
|
||||
try {
|
||||
list = getList(
|
||||
Integer.parseInt(Stapler.getCurrentRequest().getParameter("start")),
|
||||
Integer.parseInt(Stapler.getCurrentRequest().getParameter("end")));
|
||||
} catch (NumberFormatException e) {
|
||||
list = getList();
|
||||
}
|
||||
|
||||
for (hudson.tasks.test.TestResult o: list) {
|
||||
data.add(((double) o.getDuration()) / (1000), "", new ChartLabel(o) {
|
||||
@Override
|
||||
public Color getColor() {
|
||||
if (o.getFailCount() > 0)
|
||||
return ColorPalette.RED;
|
||||
else if (o.getSkipCount() > 0)
|
||||
return ColorPalette.YELLOW;
|
||||
else
|
||||
return ColorPalette.BLUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Graph of # of tests over time.
|
||||
*/
|
||||
public Graph getCountGraph() {
|
||||
return new GraphImpl("") {
|
||||
protected DataSetBuilder<String, ChartLabel> createDataSet() {
|
||||
DataSetBuilder<String, ChartLabel> data = new DataSetBuilder<String, ChartLabel>();
|
||||
|
||||
List<TestResult> list;
|
||||
try {
|
||||
list = getList(
|
||||
Integer.parseInt(Stapler.getCurrentRequest().getParameter("start")),
|
||||
Integer.parseInt(Stapler.getCurrentRequest().getParameter("end")));
|
||||
} catch (NumberFormatException e) {
|
||||
list = getList();
|
||||
}
|
||||
|
||||
for (TestResult o: list) {
|
||||
data.add(o.getPassCount(), "2Passed", new ChartLabel(o));
|
||||
data.add(o.getFailCount(), "1Failed", new ChartLabel(o));
|
||||
data.add(o.getSkipCount(), "0Skipped", new ChartLabel(o));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private abstract class GraphImpl extends Graph {
|
||||
private final String yLabel;
|
||||
|
||||
protected GraphImpl(String yLabel) {
|
||||
super(-1,600,300); // cannot use timestamp, since ranges may change
|
||||
this.yLabel = yLabel;
|
||||
}
|
||||
|
||||
protected abstract DataSetBuilder<String, ChartLabel> createDataSet();
|
||||
|
||||
protected JFreeChart createGraph() {
|
||||
final CategoryDataset dataset = createDataSet().build();
|
||||
|
||||
final JFreeChart chart = ChartFactory.createStackedAreaChart(null, // chart
|
||||
// title
|
||||
null, // unused
|
||||
yLabel, // range axis label
|
||||
dataset, // data
|
||||
PlotOrientation.VERTICAL, // orientation
|
||||
false, // include legend
|
||||
true, // tooltips
|
||||
false // urls
|
||||
);
|
||||
|
||||
chart.setBackgroundPaint(Color.white);
|
||||
|
||||
final CategoryPlot plot = chart.getCategoryPlot();
|
||||
|
||||
// plot.setAxisOffset(new Spacer(Spacer.ABSOLUTE, 5.0, 5.0, 5.0, 5.0));
|
||||
plot.setBackgroundPaint(Color.WHITE);
|
||||
plot.setOutlinePaint(null);
|
||||
plot.setForegroundAlpha(0.8f);
|
||||
// plot.setDomainGridlinesVisible(true);
|
||||
// plot.setDomainGridlinePaint(Color.white);
|
||||
plot.setRangeGridlinesVisible(true);
|
||||
plot.setRangeGridlinePaint(Color.black);
|
||||
|
||||
CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
|
||||
plot.setDomainAxis(domainAxis);
|
||||
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
|
||||
domainAxis.setLowerMargin(0.0);
|
||||
domainAxis.setUpperMargin(0.0);
|
||||
domainAxis.setCategoryMargin(0.0);
|
||||
|
||||
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
|
||||
ChartUtil.adjustChebyshev(dataset, rangeAxis);
|
||||
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
rangeAxis.setAutoRange(true);
|
||||
|
||||
StackedAreaRenderer ar = new StackedAreaRenderer2() {
|
||||
@Override
|
||||
public Paint getItemPaint(int row, int column) {
|
||||
ChartLabel key = (ChartLabel) dataset.getColumnKey(column);
|
||||
if (key.getColor() != null) return key.getColor();
|
||||
return super.getItemPaint(row, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateURL(CategoryDataset dataset, int row,
|
||||
int column) {
|
||||
ChartLabel label = (ChartLabel) dataset.getColumnKey(column);
|
||||
return label.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateToolTip(CategoryDataset dataset, int row,
|
||||
int column) {
|
||||
ChartLabel label = (ChartLabel) dataset.getColumnKey(column);
|
||||
return label.o.getOwner().getDisplayName() + " : "
|
||||
+ label.o.getDurationString();
|
||||
}
|
||||
};
|
||||
plot.setRenderer(ar);
|
||||
ar.setSeriesPaint(0,ColorPalette.YELLOW); // Skips.
|
||||
ar.setSeriesPaint(1,ColorPalette.RED); // Failures.
|
||||
ar.setSeriesPaint(2,ColorPalette.BLUE); // Total.
|
||||
|
||||
// crop extra space around the graph
|
||||
plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));
|
||||
|
||||
return chart;
|
||||
}
|
||||
}
|
||||
|
||||
class ChartLabel implements Comparable<ChartLabel> {
|
||||
TestResult o;
|
||||
String url;
|
||||
public ChartLabel(TestResult o) {
|
||||
this.o = o;
|
||||
this.url = null;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
if (this.url == null) generateUrl();
|
||||
return url;
|
||||
}
|
||||
|
||||
private void generateUrl() {
|
||||
AbstractBuild<?,?> build = o.getOwner();
|
||||
String buildLink = build.getUrl();
|
||||
String actionUrl = o.getTestResultAction().getUrlName();
|
||||
this.url = Jenkins.getInstance().getRootUrl() + buildLink + actionUrl + o.getUrl();
|
||||
}
|
||||
|
||||
public int compareTo(ChartLabel that) {
|
||||
return this.o.getOwner().number - that.o.getOwner().number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ChartLabel)) {
|
||||
return false;
|
||||
}
|
||||
ChartLabel that = (ChartLabel) o;
|
||||
return this.o == that.o;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return o.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String l = o.getOwner().getDisplayName();
|
||||
String s = o.getOwner().getBuiltOnStr();
|
||||
if (s != null)
|
||||
l += ' ' + s;
|
||||
return l;
|
||||
// return o.getDisplayName() + " " + o.getOwner().getDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int asInt(String s, int defalutValue) {
|
||||
if (s==null) return defalutValue;
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return defalutValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.tasks.test.TestResultParser;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.*;
|
||||
import hudson.remoting.VirtualChannel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
|
||||
/**
|
||||
* Parse some JUnit xml files and generate a TestResult containing all the
|
||||
* results parsed.
|
||||
*/
|
||||
@Extension
|
||||
public class JUnitParser extends TestResultParser {
|
||||
|
||||
private final boolean keepLongStdio;
|
||||
|
||||
/** TODO TestResultParser.all does not seem to ever be called so why must this be an Extension? */
|
||||
@Deprecated
|
||||
public JUnitParser() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keepLongStdio if true, retain a suite's complete stdout/stderr even if this is huge and the suite passed
|
||||
* @since 1.358
|
||||
*/
|
||||
public JUnitParser(boolean keepLongStdio) {
|
||||
this.keepLongStdio = keepLongStdio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Messages.JUnitParser_DisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestResultLocationMessage() {
|
||||
return Messages.JUnitParser_TestResultLocationMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResult parse(String testResultLocations,
|
||||
AbstractBuild build, Launcher launcher,
|
||||
TaskListener listener)
|
||||
throws InterruptedException, IOException
|
||||
{
|
||||
final long buildTime = build.getTimestamp().getTimeInMillis();
|
||||
final long timeOnMaster = System.currentTimeMillis();
|
||||
|
||||
// [BUG 3123310] TODO - Test Result Refactor: review and fix TestDataPublisher/TestAction subsystem]
|
||||
// also get code that deals with testDataPublishers from JUnitResultArchiver.perform
|
||||
|
||||
FilePath workspace = build.getWorkspace();
|
||||
if (workspace == null) {
|
||||
throw new AbortException(Messages.JUnitParser_no_workspace_found(build));
|
||||
}
|
||||
return workspace.act(new ParseResultCallable(testResultLocations, buildTime, timeOnMaster, keepLongStdio));
|
||||
}
|
||||
|
||||
private static final class ParseResultCallable implements
|
||||
FilePath.FileCallable<TestResult> {
|
||||
private final long buildTime;
|
||||
private final String testResults;
|
||||
private final long nowMaster;
|
||||
private final boolean keepLongStdio;
|
||||
|
||||
private ParseResultCallable(String testResults, long buildTime, long nowMaster, boolean keepLongStdio) {
|
||||
this.buildTime = buildTime;
|
||||
this.testResults = testResults;
|
||||
this.nowMaster = nowMaster;
|
||||
this.keepLongStdio = keepLongStdio;
|
||||
}
|
||||
|
||||
public TestResult invoke(File ws, VirtualChannel channel) throws IOException {
|
||||
final long nowSlave = System.currentTimeMillis();
|
||||
|
||||
FileSet fs = Util.createFileSet(ws, testResults);
|
||||
DirectoryScanner ds = fs.getDirectoryScanner();
|
||||
|
||||
String[] files = ds.getIncludedFiles();
|
||||
if (files.length == 0) {
|
||||
// no test result. Most likely a configuration
|
||||
// error or fatal problem
|
||||
throw new AbortException(Messages.JUnitResultArchiver_NoTestReportFound());
|
||||
}
|
||||
|
||||
TestResult result = new TestResult(buildTime + (nowSlave - nowMaster), ds, keepLongStdio);
|
||||
result.tally();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Martin Eigenbrodt,
|
||||
* Tom Huybrechts, Yahoo!, Inc., Richard Hierlmeier
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.AbortException;
|
||||
import hudson.Extension;
|
||||
import hudson.FilePath;
|
||||
import hudson.Launcher;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Action;
|
||||
import hudson.model.BuildListener;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.model.Result;
|
||||
import hudson.model.Saveable;
|
||||
import hudson.tasks.BuildStepDescriptor;
|
||||
import hudson.tasks.BuildStepMonitor;
|
||||
import hudson.tasks.Publisher;
|
||||
import hudson.tasks.Recorder;
|
||||
import hudson.tasks.junit.TestResultAction.Data;
|
||||
import hudson.tasks.test.TestResultProjectAction;
|
||||
import hudson.util.DescribableList;
|
||||
import hudson.util.FormValidation;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.kohsuke.stapler.AncestorInPath;
|
||||
import org.kohsuke.stapler.DataBoundConstructor;
|
||||
import org.kohsuke.stapler.QueryParameter;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Generates HTML report from JUnit test result XML files.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class JUnitResultArchiver extends Recorder {
|
||||
|
||||
/**
|
||||
* {@link FileSet} "includes" string, like "foo/bar/*.xml"
|
||||
*/
|
||||
private final String testResults;
|
||||
|
||||
/**
|
||||
* If true, retain a suite's complete stdout/stderr even if this is huge and the suite passed.
|
||||
* @since 1.358
|
||||
*/
|
||||
private final boolean keepLongStdio;
|
||||
|
||||
/**
|
||||
* {@link TestDataPublisher}s configured for this archiver, to process the recorded data.
|
||||
* For compatibility reasons, can be null.
|
||||
* @since 1.320
|
||||
*/
|
||||
private final DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> testDataPublishers;
|
||||
|
||||
private final Double healthScaleFactor;
|
||||
|
||||
/**
|
||||
* left for backwards compatibility
|
||||
* @deprecated since 2009-08-09.
|
||||
*/
|
||||
@Deprecated
|
||||
public JUnitResultArchiver(String testResults) {
|
||||
this(testResults, false, null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public JUnitResultArchiver(String testResults,
|
||||
DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> testDataPublishers) {
|
||||
this(testResults, false, testDataPublishers);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public JUnitResultArchiver(
|
||||
String testResults,
|
||||
boolean keepLongStdio,
|
||||
DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> testDataPublishers) {
|
||||
this(testResults, keepLongStdio, testDataPublishers, 1.0);
|
||||
}
|
||||
|
||||
@DataBoundConstructor
|
||||
public JUnitResultArchiver(
|
||||
String testResults,
|
||||
boolean keepLongStdio,
|
||||
DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> testDataPublishers,
|
||||
double healthScaleFactor) {
|
||||
this.testResults = testResults;
|
||||
this.keepLongStdio = keepLongStdio;
|
||||
this.testDataPublishers = testDataPublishers;
|
||||
this.healthScaleFactor = Math.max(0.0,healthScaleFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* In progress. Working on delegating the actual parsing to the JUnitParser.
|
||||
*/
|
||||
protected TestResult parse(String expandedTestResults, AbstractBuild build, Launcher launcher, BuildListener listener)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
return new JUnitParser(isKeepLongStdio()).parse(expandedTestResults, build, launcher, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform(AbstractBuild build, Launcher launcher,
|
||||
BuildListener listener) throws InterruptedException, IOException {
|
||||
listener.getLogger().println(Messages.JUnitResultArchiver_Recording());
|
||||
TestResultAction action;
|
||||
|
||||
final String testResults = build.getEnvironment(listener).expand(this.testResults);
|
||||
|
||||
try {
|
||||
TestResult result = parse(testResults, build, launcher, listener);
|
||||
|
||||
try {
|
||||
// TODO can the build argument be omitted now, or is it used prior to the call to addAction?
|
||||
action = new TestResultAction(build, result, listener);
|
||||
} catch (NullPointerException npe) {
|
||||
throw new AbortException(Messages.JUnitResultArchiver_BadXML(testResults));
|
||||
}
|
||||
action.setHealthScaleFactor(getHealthScaleFactor()); // TODO do we want to move this to the constructor?
|
||||
result.freeze(action);
|
||||
if (result.isEmpty()) {
|
||||
// most likely a configuration error in the job - e.g. false pattern to match the JUnit result files
|
||||
throw new AbortException(Messages.JUnitResultArchiver_ResultIsEmpty());
|
||||
}
|
||||
|
||||
// TODO: Move into JUnitParser [BUG 3123310]
|
||||
List<Data> data = new ArrayList<Data>();
|
||||
if (testDataPublishers != null) {
|
||||
for (TestDataPublisher tdp : testDataPublishers) {
|
||||
Data d = tdp.getTestData(build, launcher, listener, result);
|
||||
if (d != null) {
|
||||
data.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action.setData(data);
|
||||
} catch (AbortException e) {
|
||||
if (build.getResult() == Result.FAILURE)
|
||||
// most likely a build failed before it gets to the test phase.
|
||||
// don't report confusing error message.
|
||||
return true;
|
||||
|
||||
listener.getLogger().println(e.getMessage());
|
||||
build.setResult(Result.FAILURE);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(listener.error("Failed to archive test reports"));
|
||||
build.setResult(Result.FAILURE);
|
||||
return true;
|
||||
}
|
||||
|
||||
build.addAction(action);
|
||||
|
||||
if (action.getResult().getFailCount() > 0)
|
||||
build.setResult(Result.UNSTABLE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not actually used, but left for backward compatibility
|
||||
*
|
||||
* @deprecated since 2009-08-10.
|
||||
*/
|
||||
protected TestResult parseResult(DirectoryScanner ds, long buildTime)
|
||||
throws IOException {
|
||||
return new TestResult(buildTime, ds);
|
||||
}
|
||||
|
||||
public BuildStepMonitor getRequiredMonitorService() {
|
||||
return BuildStepMonitor.NONE;
|
||||
}
|
||||
|
||||
public String getTestResults() {
|
||||
return testResults;
|
||||
}
|
||||
|
||||
public double getHealthScaleFactor() {
|
||||
return healthScaleFactor == null ? 1.0 : healthScaleFactor;
|
||||
}
|
||||
|
||||
public DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> getTestDataPublishers() {
|
||||
return testDataPublishers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getProjectActions(AbstractProject<?, ?> project) {
|
||||
return Collections.<Action>singleton(new TestResultProjectAction(project));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the keepLongStdio
|
||||
*/
|
||||
public boolean isKeepLongStdio() {
|
||||
return keepLongStdio;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Extension
|
||||
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
|
||||
public String getDisplayName() {
|
||||
return Messages.JUnitResultArchiver_DisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpFile() {
|
||||
return "/help/tasks/junit/report.html";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher newInstance(StaplerRequest req, JSONObject formData)
|
||||
throws hudson.model.Descriptor.FormException {
|
||||
String testResults = formData.getString("testResults");
|
||||
boolean keepLongStdio = formData.getBoolean("keepLongStdio");
|
||||
DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>> testDataPublishers = new DescribableList<TestDataPublisher, Descriptor<TestDataPublisher>>(Saveable.NOOP);
|
||||
try {
|
||||
testDataPublishers.rebuild(req, formData, TestDataPublisher.all());
|
||||
} catch (IOException e) {
|
||||
throw new FormException(e,null);
|
||||
}
|
||||
|
||||
return new JUnitResultArchiver(testResults, keepLongStdio, testDataPublishers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs on-the-fly validation on the file mask wildcard.
|
||||
*/
|
||||
public FormValidation doCheckTestResults(
|
||||
@AncestorInPath AbstractProject project,
|
||||
@QueryParameter String value) throws IOException {
|
||||
return FilePath.validateFileMask(project.getSomeWorkspace(), value);
|
||||
}
|
||||
|
||||
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public FormValidation doCheckHealthScaleFactor(@QueryParameter double value) {
|
||||
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,306 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.tasks.test.MetaTabulatedResult;
|
||||
import hudson.tasks.test.TestResult;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Cumulative test result for a package.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public final class PackageResult extends MetaTabulatedResult implements Comparable<PackageResult> {
|
||||
|
||||
private final String packageName;
|
||||
private transient String safeName;
|
||||
/**
|
||||
* All {@link ClassResult}s keyed by their short name.
|
||||
*/
|
||||
private final Map<String,ClassResult> classes = new TreeMap<String,ClassResult>();
|
||||
private int passCount,failCount,skipCount;
|
||||
private final hudson.tasks.junit.TestResult parent;
|
||||
private float duration;
|
||||
|
||||
PackageResult(hudson.tasks.junit.TestResult parent, String packageName) {
|
||||
this.packageName = packageName;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractBuild<?, ?> getOwner() {
|
||||
return (parent == null ? null : parent.getOwner());
|
||||
}
|
||||
|
||||
public hudson.tasks.junit.TestResult getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
public String getName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getSafeName() {
|
||||
if (safeName != null) {
|
||||
return safeName;
|
||||
}
|
||||
Collection<PackageResult> siblings = (parent == null ? Collections.EMPTY_LIST : parent.getChildren());
|
||||
return safeName = uniquifyName(
|
||||
siblings,
|
||||
safe(getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResult findCorrespondingResult(String id) {
|
||||
String myID = safe(getName());
|
||||
|
||||
int base = id.indexOf(myID);
|
||||
String className = id; // fall back value
|
||||
if (base > 0) {
|
||||
int classNameStart = base + myID.length() + 1;
|
||||
if (classNameStart<id.length())
|
||||
className = id.substring(classNameStart);
|
||||
}
|
||||
|
||||
String subId = null;
|
||||
int classNameEnd = className.indexOf('/');
|
||||
if (classNameEnd > 0) {
|
||||
subId = className.substring(classNameEnd + 1);
|
||||
if (subId.length() == 0) {
|
||||
subId = null;
|
||||
}
|
||||
className = className.substring(0, classNameEnd);
|
||||
}
|
||||
|
||||
ClassResult child = getClassResult(className);
|
||||
if (child != null && subId != null)
|
||||
return child.findCorrespondingResult(subId);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Messages.PackageResult_getTitle(getDisplayName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChildTitle() {
|
||||
return Messages.PackageResult_getChildTitle();
|
||||
}
|
||||
|
||||
// TODO: wait until stapler 1.60 to do this @Exported
|
||||
@Override
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Exported
|
||||
@Override
|
||||
public int getPassCount() {
|
||||
return passCount;
|
||||
}
|
||||
|
||||
@Exported
|
||||
@Override
|
||||
public int getFailCount() {
|
||||
return failCount;
|
||||
}
|
||||
|
||||
@Exported
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
return skipCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDynamic(String name, StaplerRequest req, StaplerResponse rsp) {
|
||||
ClassResult result = getClassResult(name);
|
||||
if (result != null) {
|
||||
return result;
|
||||
} else {
|
||||
return super.getDynamic(name, req, rsp);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassResult getClassResult(String name) {
|
||||
return classes.get(name);
|
||||
}
|
||||
|
||||
@Exported(name="child")
|
||||
public Collection<ClassResult> getChildren() {
|
||||
return classes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this test result has children.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasChildren() {
|
||||
int totalTests = passCount + failCount + skipCount;
|
||||
return (totalTests != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the failed cases, in no particular
|
||||
* sort order
|
||||
*/
|
||||
public List<CaseResult> getFailedTests() {
|
||||
List<CaseResult> r = new ArrayList<CaseResult>();
|
||||
for (ClassResult clr : classes.values()) {
|
||||
for (CaseResult cr : clr.getChildren()) {
|
||||
if (cr.isFailed()) {
|
||||
r.add(cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the failed cases, sorted by age.
|
||||
*/
|
||||
public List<CaseResult> getFailedTestsSortedByAge() {
|
||||
List<CaseResult> failedTests = getFailedTests();
|
||||
Collections.sort(failedTests, CaseResult.BY_AGE);
|
||||
return failedTests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that passed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends hudson.tasks.test.TestResult> getPassedTests() {
|
||||
List<CaseResult> r = new ArrayList<CaseResult>();
|
||||
for (ClassResult clr : classes.values()) {
|
||||
for (CaseResult cr : clr.getChildren()) {
|
||||
if (cr.isPassed()) {
|
||||
r.add(cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(r,CaseResult.BY_AGE);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that were skipped
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty list
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getSkippedTests() {
|
||||
List<CaseResult> r = new ArrayList<CaseResult>();
|
||||
for (ClassResult clr : classes.values()) {
|
||||
for (CaseResult cr : clr.getChildren()) {
|
||||
if (cr.isSkipped()) {
|
||||
r.add(cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(r, CaseResult.BY_AGE);
|
||||
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)
|
||||
// }
|
||||
/**
|
||||
* @return true if every test was not skipped and every test did not fail, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPassed() {
|
||||
return (failCount == 0 && skipCount == 0);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
c.add(r);
|
||||
duration += r.getDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recount my children
|
||||
*/
|
||||
@Override
|
||||
public void tally() {
|
||||
passCount = 0;
|
||||
failCount = 0;
|
||||
skipCount = 0;
|
||||
duration = 0;
|
||||
|
||||
for (ClassResult cr : classes.values()) {
|
||||
cr.tally();
|
||||
passCount += cr.getPassCount();
|
||||
failCount += cr.getFailCount();
|
||||
skipCount += cr.getSkipCount();
|
||||
duration += cr.getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
void freeze() {
|
||||
passCount = failCount = skipCount = 0;
|
||||
for (ClassResult cr : classes.values()) {
|
||||
cr.freeze();
|
||||
passCount += cr.getPassCount();
|
||||
failCount += cr.getFailCount();
|
||||
skipCount += cr.getSkipCount();
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(PackageResult that) {
|
||||
return this.packageName.compareTo(that.packageName);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return TestNameTransformer.getTransformedName(packageName);
|
||||
}
|
||||
}
|
|
@ -1,332 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt, Xavier Le Vourch, Tom Huybrechts, Yahoo!, Inc., Victor Garcia
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.tasks.test.TestObject;
|
||||
import hudson.util.io.ParserConfigurator;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Result of one test suite.
|
||||
*
|
||||
* <p>
|
||||
* The notion of "test suite" is rather arbitrary in JUnit ant task.
|
||||
* It's basically one invocation of junit.
|
||||
*
|
||||
* <p>
|
||||
* This object is really only used as a part of the persisted
|
||||
* object tree.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public final class SuiteResult implements Serializable {
|
||||
private final String file;
|
||||
private final String name;
|
||||
private final String stdout;
|
||||
private final String stderr;
|
||||
private float duration;
|
||||
/**
|
||||
* The 'timestamp' attribute of the test suite.
|
||||
* AFAICT, this is not a required attribute in XML, so the value may be null.
|
||||
*/
|
||||
private String timestamp;
|
||||
/** Optional ID attribute of a test suite. E.g., Eclipse plug-ins tests always have the name 'tests' but a different id. **/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* All test cases.
|
||||
*/
|
||||
private final List<CaseResult> cases = new ArrayList<CaseResult>();
|
||||
private transient Map<String,CaseResult> casesByName;
|
||||
private transient hudson.tasks.junit.TestResult parent;
|
||||
|
||||
SuiteResult(String name, String stdout, String stderr) {
|
||||
this.name = name;
|
||||
this.stderr = stderr;
|
||||
this.stdout = stdout;
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
private synchronized Map<String,CaseResult> casesByName() {
|
||||
if (casesByName == null) {
|
||||
casesByName = new HashMap<String,CaseResult>();
|
||||
for (CaseResult c : cases) {
|
||||
casesByName.put(c.getName(), c);
|
||||
}
|
||||
}
|
||||
return casesByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passed to {@link ParserConfigurator}.
|
||||
* @since 1.416
|
||||
*/
|
||||
public static class SuiteResultParserConfigurationContext {
|
||||
public final File xmlReport;
|
||||
|
||||
SuiteResultParserConfigurationContext(File xmlReport) {
|
||||
this.xmlReport = xmlReport;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the JUnit XML file into {@link SuiteResult}s.
|
||||
* This method returns a collection, as a single XML may have multiple <testsuite>
|
||||
* elements wrapped into the top-level <testsuites>.
|
||||
*/
|
||||
static List<SuiteResult> parse(File xmlReport, boolean keepLongStdio) throws DocumentException, IOException, InterruptedException {
|
||||
List<SuiteResult> r = new ArrayList<SuiteResult>();
|
||||
|
||||
// parse into DOM
|
||||
SAXReader saxReader = new SAXReader();
|
||||
ParserConfigurator.applyConfiguration(saxReader,new SuiteResultParserConfigurationContext(xmlReport));
|
||||
|
||||
Document result = saxReader.read(xmlReport);
|
||||
Element root = result.getRootElement();
|
||||
|
||||
parseSuite(xmlReport,keepLongStdio,r,root);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private static void parseSuite(File xmlReport, boolean keepLongStdio, List<SuiteResult> r, Element root) throws DocumentException, IOException {
|
||||
// nested test suites
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> testSuites = (List<Element>)root.elements("testsuite");
|
||||
for (Element suite : testSuites)
|
||||
parseSuite(xmlReport, keepLongStdio, r, suite);
|
||||
|
||||
// child test cases
|
||||
// FIXME: do this also if no testcases!
|
||||
if (root.element("testcase")!=null || root.element("error")!=null)
|
||||
r.add(new SuiteResult(xmlReport, root, keepLongStdio));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, boolean keepLongStdio) throws DocumentException, IOException {
|
||||
this.file = xmlReport.getAbsolutePath();
|
||||
String name = suite.attributeValue("name");
|
||||
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 {
|
||||
String pkg = suite.attributeValue("package");
|
||||
if(pkg!=null&& pkg.length()>0) name=pkg+'.'+name;
|
||||
}
|
||||
this.name = TestObject.safe(name);
|
||||
this.timestamp = suite.attributeValue("timestamp");
|
||||
this.id = suite.attributeValue("id");
|
||||
|
||||
Element ex = suite.element("error");
|
||||
if(ex!=null) {
|
||||
// according to junit-noframes.xsl l.229, this happens when the test class failed to load
|
||||
addCase(new CaseResult(this, suite, "<init>", keepLongStdio));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> testCases = (List<Element>)suite.elements("testcase");
|
||||
for (Element e : testCases) {
|
||||
// https://issues.jenkins-ci.org/browse/JENKINS-1233 indicates that
|
||||
// when <testsuites> is present, we are better off using @classname on the
|
||||
// individual testcase class.
|
||||
|
||||
// https://issues.jenkins-ci.org/browse/JENKINS-1463 indicates that
|
||||
// @classname may not exist in individual testcase elements. We now
|
||||
// also test if the testsuite element has a package name that can be used
|
||||
// as the class name instead of the file name which is default.
|
||||
String classname = e.attributeValue("classname");
|
||||
if (classname == null) {
|
||||
classname = suite.attributeValue("name");
|
||||
}
|
||||
|
||||
// https://issues.jenkins-ci.org/browse/JENKINS-1233 and
|
||||
// http://www.nabble.com/difference-in-junit-publisher-and-ant-junitreport-tf4308604.html#a12265700
|
||||
// are at odds with each other --- when both are present,
|
||||
// one wants to use @name from <testsuite>,
|
||||
// the other wants to use @classname from <testcase>.
|
||||
|
||||
addCase(new CaseResult(this, e, classname, keepLongStdio));
|
||||
}
|
||||
|
||||
String stdout = CaseResult.possiblyTrimStdio(cases, keepLongStdio, suite.elementText("system-out"));
|
||||
String stderr = CaseResult.possiblyTrimStdio(cases, keepLongStdio, 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}).
|
||||
Matcher m = SUREFIRE_FILENAME.matcher(xmlReport.getName());
|
||||
if (m.matches()) {
|
||||
// look for ***-output.txt from TEST-***.xml
|
||||
File mavenOutputFile = new File(xmlReport.getParentFile(),m.group(1)+"-output.txt");
|
||||
if (mavenOutputFile.exists()) {
|
||||
try {
|
||||
stdout = CaseResult.possiblyTrimStdio(cases, keepLongStdio, mavenOutputFile);
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Failed to read "+mavenOutputFile,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.stdout = stdout;
|
||||
this.stderr = stderr;
|
||||
}
|
||||
|
||||
/*package*/ void addCase(CaseResult cr) {
|
||||
cases.add(cr);
|
||||
casesByName().put(cr.getName(), cr);
|
||||
duration += cr.getDuration();
|
||||
}
|
||||
|
||||
@Exported(visibility=9)
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Exported(visibility=9)
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stdout of this test.
|
||||
*
|
||||
* @since 1.281
|
||||
* @see CaseResult#getStdout()
|
||||
*/
|
||||
@Exported
|
||||
public String getStdout() {
|
||||
return stdout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stderr of this test.
|
||||
*
|
||||
* @since 1.281
|
||||
* @see CaseResult#getStderr()
|
||||
*/
|
||||
@Exported
|
||||
public String getStderr() {
|
||||
return stderr;
|
||||
}
|
||||
|
||||
/**
|
||||
* The absolute path to the original test report. OS-dependent.
|
||||
*/
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public hudson.tasks.junit.TestResult getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Exported(visibility=9)
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Exported(visibility=9)
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Exported(inline=true,visibility=9)
|
||||
public List<CaseResult> 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);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CaseResult} whose {@link CaseResult#getName()}
|
||||
* is the same as the given string.
|
||||
*
|
||||
* <p>
|
||||
* Note that test name needs not be unique.
|
||||
*/
|
||||
public CaseResult getCase(String name) {
|
||||
return casesByName().get(name);
|
||||
}
|
||||
|
||||
public Set<String> getClassNames() {
|
||||
Set<String> result = new HashSet<String>();
|
||||
for (CaseResult c : cases) {
|
||||
result.add(c.getClassName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** KLUGE. We have to call this to prevent freeze()
|
||||
* from calling c.freeze() on all its children,
|
||||
* because that in turn calls c.getOwner(),
|
||||
* which requires a non-null parent.
|
||||
* @param parent
|
||||
*/
|
||||
void setParent(hudson.tasks.junit.TestResult parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*package*/ boolean freeze(hudson.tasks.junit.TestResult owner) {
|
||||
if(this.parent!=null)
|
||||
return false; // already frozen
|
||||
|
||||
this.parent = owner;
|
||||
for (CaseResult c : cases)
|
||||
c.freeze(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Pattern SUREFIRE_FILENAME = Pattern.compile("TEST-(.+)\\.xml");
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.Action;
|
||||
|
||||
/**
|
||||
*
|
||||
* Jelly (all optional):
|
||||
* <ul>
|
||||
* <li>index.jelly: included at the top of the test page</li>
|
||||
* <li>summary.jelly: included in a collapsed panel on the test parent page</li>
|
||||
* <li>badge.jelly: shown after the test link on the test parent page</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author tom
|
||||
* @since 1.320
|
||||
* @see TestDataPublisher
|
||||
*/
|
||||
public abstract class TestAction implements Action {
|
||||
|
||||
/**
|
||||
* Returns text with annotations.
|
||||
*/
|
||||
public String annotate(String text) {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.DescriptorExtensionList;
|
||||
import hudson.Extension;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.Launcher;
|
||||
import hudson.model.*;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Contributes {@link TestAction}s to test results.
|
||||
*
|
||||
* This enables plugins to annotate test results and provide richer UI, such as letting users
|
||||
* claim test failures, allowing people to file bugs, or more generally, additional actions, views, etc.
|
||||
*
|
||||
* <p>
|
||||
* To register your implementation, put {@link Extension} on your descriptor implementation.
|
||||
*
|
||||
* @since 1.320
|
||||
*/
|
||||
public abstract class TestDataPublisher extends AbstractDescribableImpl<TestDataPublisher> implements ExtensionPoint {
|
||||
|
||||
/**
|
||||
* Called after test results are collected by Jenkins, to create a resolver for {@link TestAction}s.
|
||||
*
|
||||
* @return
|
||||
* can be null to indicate that there's nothing to contribute for this test result.
|
||||
*/
|
||||
public abstract TestResultAction.Data getTestData(
|
||||
AbstractBuild<?, ?> build, Launcher launcher,
|
||||
BuildListener listener, TestResult testResult) throws IOException, InterruptedException;
|
||||
|
||||
public static DescriptorExtensionList<TestDataPublisher, Descriptor<TestDataPublisher>> all() {
|
||||
return Jenkins.getInstance().<TestDataPublisher, Descriptor<TestDataPublisher>>getDescriptorList(TestDataPublisher.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
/**
|
||||
* Allow extensions to transform the class/package/method name for JUnit test
|
||||
* cases which will be displayed on the test result page.
|
||||
*
|
||||
* This is useful for alternative JVM languages like Scala that allow
|
||||
* identifiers with invalid characters by encoding them: an extension can
|
||||
* decode the identifier so it is displayed correctly.
|
||||
*
|
||||
* @since 1.515
|
||||
*/
|
||||
|
||||
public abstract class TestNameTransformer implements ExtensionPoint {
|
||||
/**
|
||||
* Transform the class/package/method name.
|
||||
*
|
||||
* @param name
|
||||
* Class name (may be simple or fully qualified), package name, or
|
||||
* method name from a JUnit test.
|
||||
* @return
|
||||
* The transformed name, or the name that was passed in if it doesn't
|
||||
* need to be changed.
|
||||
*/
|
||||
public abstract String transformName(String name);
|
||||
|
||||
public static String getTransformedName(String name) {
|
||||
String transformedName = name;
|
||||
for (TestNameTransformer transformer : all()) {
|
||||
transformedName = transformer.transformName(transformedName);
|
||||
}
|
||||
return transformedName;
|
||||
}
|
||||
|
||||
public static ExtensionList<TestNameTransformer> all() {
|
||||
return ExtensionList.lookup(TestNameTransformer.class);
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractModelObject;
|
||||
import hudson.model.Api;
|
||||
import hudson.tasks.test.AbstractTestResultAction;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Stub of base class for all test result objects. The real implementation of
|
||||
* the TestObject is in hudson.tasks.test.TestObject. This class simply
|
||||
* defines abstract methods so that legacy code will continue to compile.
|
||||
*
|
||||
* @deprecated
|
||||
* Use {@link hudson.tasks.test.TestObject} instead.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public abstract class TestObject extends AbstractModelObject implements Serializable {
|
||||
public abstract AbstractBuild<?,?> getOwner() ;
|
||||
|
||||
|
||||
public abstract TestObject getParent();
|
||||
|
||||
public abstract String getId();
|
||||
/**
|
||||
* Returns url relative to TestResult
|
||||
*/
|
||||
public abstract String getUrl();
|
||||
|
||||
public abstract TestResult getTestResult();
|
||||
|
||||
public abstract AbstractTestResultAction getTestResultAction();
|
||||
|
||||
public abstract List<TestAction> getTestActions();
|
||||
|
||||
public abstract <T> T getTestAction(Class<T> 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();
|
||||
|
||||
public abstract TestObject getResultInBuild(AbstractBuild<?,?> build);
|
||||
|
||||
/**
|
||||
* Time took to run this test. In seconds.
|
||||
*/
|
||||
public abstract float getDuration();
|
||||
|
||||
/**
|
||||
* Returns the string representation of the {@link #getDuration()}, in a
|
||||
* human readable format.
|
||||
*/
|
||||
public abstract String getDurationString();
|
||||
|
||||
public abstract String getDescription();
|
||||
|
||||
public abstract void setDescription(String description);
|
||||
|
||||
/**
|
||||
* Exposes this object through the remote API.
|
||||
*/
|
||||
public abstract Api getApi();
|
||||
|
||||
/**
|
||||
* Gets the name of this object.
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Gets the version of {@link #getName()} that's URL-safe.
|
||||
*/
|
||||
public abstract String getSafeName();
|
||||
|
||||
public abstract String getSearchUrl();
|
||||
|
||||
/**
|
||||
* Gets the total number of passed tests.
|
||||
*/
|
||||
public abstract int getPassCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of failed tests.
|
||||
*/
|
||||
public abstract int getFailCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of skipped tests.
|
||||
*/
|
||||
public abstract int getSkipCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of tests.
|
||||
*/
|
||||
public abstract int getTotalCount();
|
||||
|
||||
public abstract History getHistory();
|
||||
|
||||
// public abstract Object getDynamic(String token, StaplerRequest req,
|
||||
// StaplerResponse rsp);
|
||||
//
|
||||
// public abstract HttpResponse doSubmitDescription(
|
||||
// @QueryParameter String description) throws IOException,
|
||||
// ServletException;
|
||||
|
||||
}
|
|
@ -1,646 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.AbortException;
|
||||
import hudson.Util;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Run;
|
||||
import hudson.tasks.test.AbstractTestResultAction;
|
||||
import hudson.tasks.test.MetaTabulatedResult;
|
||||
import hudson.tasks.test.TestObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
||||
/**
|
||||
* Root of all the test results for one build.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public final class TestResult extends MetaTabulatedResult {
|
||||
|
||||
/**
|
||||
* List of all {@link SuiteResult}s in this test.
|
||||
* This is the core data structure to be persisted in the disk.
|
||||
*/
|
||||
private final List<SuiteResult> suites = new ArrayList<SuiteResult>();
|
||||
|
||||
/**
|
||||
* {@link #suites} keyed by their names for faster lookup.
|
||||
*/
|
||||
private transient Map<String,SuiteResult> suitesByName;
|
||||
|
||||
/**
|
||||
* Results tabulated by package.
|
||||
*/
|
||||
private transient Map<String,PackageResult> byPackages;
|
||||
|
||||
// set during the freeze phase
|
||||
private transient AbstractTestResultAction parentAction;
|
||||
|
||||
private transient TestObject parent;
|
||||
|
||||
/**
|
||||
* Number of all tests.
|
||||
*/
|
||||
private transient int totalTests;
|
||||
|
||||
private transient int skippedTests;
|
||||
|
||||
private float duration;
|
||||
|
||||
/**
|
||||
* Number of failed/error tests.
|
||||
*/
|
||||
private transient List<CaseResult> failedTests;
|
||||
|
||||
private final boolean keepLongStdio;
|
||||
|
||||
/**
|
||||
* Creates an empty result.
|
||||
*/
|
||||
public TestResult() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.522
|
||||
*/
|
||||
public TestResult(boolean keepLongStdio) {
|
||||
this.keepLongStdio = keepLongStdio;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public TestResult(long buildTime, DirectoryScanner results) throws IOException {
|
||||
this(buildTime, results, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect reports from the given {@link DirectoryScanner}, while
|
||||
* filtering out all files that were created before the given time.
|
||||
* @param keepLongStdio if true, retain a suite's complete stdout/stderr even if this is huge and the suite passed
|
||||
* @since 1.358
|
||||
*/
|
||||
public TestResult(long buildTime, DirectoryScanner results, boolean keepLongStdio) throws IOException {
|
||||
this.keepLongStdio = keepLongStdio;
|
||||
parse(buildTime, results);
|
||||
}
|
||||
|
||||
public TestObject getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(TestObject parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResult getTestResult() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect reports from the given {@link DirectoryScanner}, while
|
||||
* filtering out all files that were created before the given time.
|
||||
*/
|
||||
public void parse(long buildTime, DirectoryScanner results) throws IOException {
|
||||
String[] includedFiles = results.getIncludedFiles();
|
||||
File baseDir = results.getBasedir();
|
||||
parse(buildTime,baseDir,includedFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect reports from the given report files, while
|
||||
* filtering out all files that were created before the given time.
|
||||
*
|
||||
* @since 1.426
|
||||
*/
|
||||
public void parse(long buildTime, File baseDir, String[] reportFiles) throws IOException {
|
||||
|
||||
boolean parsed=false;
|
||||
|
||||
for (String value : reportFiles) {
|
||||
File reportFile = new File(baseDir, value);
|
||||
// only count files that were actually updated during this build
|
||||
if ( (buildTime-3000/*error margin*/ <= reportFile.lastModified())) {
|
||||
parsePossiblyEmpty(reportFile);
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
long localTime = System.currentTimeMillis();
|
||||
if(localTime < buildTime-1000) /*margin*/
|
||||
// build time is in the the future. clock on this slave must be running behind
|
||||
throw new AbortException(
|
||||
"Clock on this slave is out of sync with the master, and therefore \n" +
|
||||
"I can't figure out what test results are new and what are old.\n" +
|
||||
"Please keep the slave clock in sync with the master.");
|
||||
|
||||
File f = new File(baseDir,reportFiles[0]);
|
||||
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", f,
|
||||
Util.getTimeSpanString(buildTime-f.lastModified())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect reports from the given report files
|
||||
*
|
||||
* @since 1.500
|
||||
*/
|
||||
public void parse(long buildTime, Iterable<File> reportFiles) throws IOException {
|
||||
boolean parsed=false;
|
||||
|
||||
for (File reportFile : reportFiles) {
|
||||
// only count files that were actually updated during this build
|
||||
if ( (buildTime-3000/*error margin*/ <= reportFile.lastModified())) {
|
||||
parsePossiblyEmpty(reportFile);
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!parsed) {
|
||||
long localTime = System.currentTimeMillis();
|
||||
if(localTime < buildTime-1000) /*margin*/
|
||||
// build time is in the the future. clock on this slave must be running behind
|
||||
throw new AbortException(
|
||||
"Clock on this slave is out of sync with the master, and therefore \n" +
|
||||
"I can't figure out what test results are new and what are old.\n" +
|
||||
"Please keep the slave clock in sync with the master.");
|
||||
|
||||
File f = reportFiles.iterator().next();
|
||||
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", f,
|
||||
Util.getTimeSpanString(buildTime-f.lastModified())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parsePossiblyEmpty(File reportFile) throws IOException {
|
||||
if(reportFile.length()==0) {
|
||||
// this is a typical problem when JVM quits abnormally, like OutOfMemoryError during a test.
|
||||
SuiteResult sr = new SuiteResult(reportFile.getName(), "", "");
|
||||
sr.addCase(new CaseResult(sr,"<init>","Test report file "+reportFile.getAbsolutePath()+" was length 0"));
|
||||
add(sr);
|
||||
} else {
|
||||
parse(reportFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(SuiteResult sr) {
|
||||
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()) && nullSafeEq(s.getId(),sr.getId())) {
|
||||
|
||||
// However, a common problem is that people parse TEST-*.xml as well as TESTS-TestSuite.xml.
|
||||
// In that case consider the result file as a duplicate and discard it.
|
||||
// see http://jenkins.361315.n4.nabble.com/Problem-with-duplicate-build-execution-td371616.html for discussion.
|
||||
if(strictEq(s.getTimestamp(),sr.getTimestamp())) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (CaseResult cr: sr.getCases()) {
|
||||
s.addCase(cr);
|
||||
cr.replaceParent(s);
|
||||
}
|
||||
duration += sr.getDuration();
|
||||
return;
|
||||
}
|
||||
}
|
||||
suites.add(sr);
|
||||
duration += sr.getDuration();
|
||||
}
|
||||
|
||||
private boolean strictEq(Object lhs, Object rhs) {
|
||||
return lhs != null && rhs != null && lhs.equals(rhs);
|
||||
}
|
||||
|
||||
private boolean nullSafeEq(Object lhs, Object rhs) {
|
||||
if (lhs == null) {
|
||||
return rhs == null;
|
||||
}
|
||||
return lhs.equals(rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an additional report file.
|
||||
*/
|
||||
public void parse(File reportFile) throws IOException {
|
||||
try {
|
||||
for (SuiteResult suiteResult : SuiteResult.parse(reportFile, keepLongStdio))
|
||||
add(suiteResult);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Failed to read "+reportFile,e);
|
||||
} catch (RuntimeException 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);
|
||||
} else {
|
||||
SuiteResult sr = new SuiteResult(reportFile.getName(), "", "");
|
||||
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,"<init>",error));
|
||||
add(sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return Messages.TestResult_getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractBuild<?,?> getOwner() {
|
||||
return (parentAction == null? null: parentAction.owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public hudson.tasks.test.TestResult findCorrespondingResult(String id) {
|
||||
if (getId().equals(id) || (id == null)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
String firstElement = null;
|
||||
String subId = null;
|
||||
int sepIndex = id.indexOf('/');
|
||||
if (sepIndex < 0) {
|
||||
firstElement = id;
|
||||
subId = null;
|
||||
} else {
|
||||
firstElement = id.substring(0, sepIndex);
|
||||
subId = id.substring(sepIndex + 1);
|
||||
if (subId.length() == 0) {
|
||||
subId = null;
|
||||
}
|
||||
}
|
||||
|
||||
String packageName = null;
|
||||
if (firstElement.equals(getId())) {
|
||||
sepIndex = subId.indexOf('/');
|
||||
if (sepIndex < 0) {
|
||||
packageName = subId;
|
||||
subId = null;
|
||||
} else {
|
||||
packageName = subId.substring(0, sepIndex);
|
||||
subId = subId.substring(sepIndex + 1);
|
||||
}
|
||||
} else {
|
||||
packageName = firstElement;
|
||||
subId = null;
|
||||
}
|
||||
PackageResult child = byPackage(packageName);
|
||||
if (child != null) {
|
||||
if (subId != null) {
|
||||
return child.findCorrespondingResult(subId);
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return Messages.TestResult_getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChildTitle() {
|
||||
return Messages.TestResult_getChildTitle();
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
@Override
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
@Override
|
||||
public int getPassCount() {
|
||||
return totalTests-getFailCount()-getSkipCount();
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
@Override
|
||||
public int getFailCount() {
|
||||
if(failedTests==null)
|
||||
return 0;
|
||||
else
|
||||
return failedTests.size();
|
||||
}
|
||||
|
||||
@Exported(visibility=999)
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
return skippedTests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this doesn't have any any test results.
|
||||
* @since 1.511
|
||||
*/
|
||||
@Exported(visibility=999)
|
||||
public boolean isEmpty() {
|
||||
return getTotalCount() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CaseResult> getFailedTests() {
|
||||
return failedTests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that passed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends hudson.tasks.test.TestResult> getPassedTests() {
|
||||
throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that were skipped
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty list
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends hudson.tasks.test.TestResult> getSkippedTests() {
|
||||
throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated)
|
||||
}
|
||||
|
||||
/**
|
||||
* If this test failed, then return the build number
|
||||
* when this test started failing.
|
||||
*/
|
||||
@Override
|
||||
public int getFailedSince() {
|
||||
throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated)
|
||||
}
|
||||
|
||||
/**
|
||||
* If this test failed, then return the run
|
||||
* when this test started failing.
|
||||
*/
|
||||
@Override
|
||||
public Run<?, ?> getFailedSinceRun() {
|
||||
throw new UnsupportedOperationException(); // TODO: implement!(FIXME: generated)
|
||||
}
|
||||
|
||||
/**
|
||||
* The stdout of this test.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Depending on the tool that produced the XML report, this method works somewhat inconsistently.
|
||||
* With some tools (such as Maven surefire plugin), you get the accurate information, that is
|
||||
* the stdout from this test case. With some other tools (such as the JUnit task in Ant), this
|
||||
* method returns the stdout produced by the entire test suite.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* If you need to know which is the case, compare this output from {@link SuiteResult#getStdout()}.
|
||||
*
|
||||
* @since 1.294
|
||||
*/
|
||||
@Override
|
||||
public String getStdout() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (SuiteResult suite: suites) {
|
||||
sb.append("Standard Out (stdout) for Suite: " + suite.getName());
|
||||
sb.append(suite.getStdout());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The stderr of this test.
|
||||
*
|
||||
* @see #getStdout()
|
||||
* @since 1.294
|
||||
*/
|
||||
@Override
|
||||
public String getStderr() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (SuiteResult suite: suites) {
|
||||
sb.append("Standard Error (stderr) for Suite: " + suite.getName());
|
||||
sb.append(suite.getStderr());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the stack trace, or otherwise null.
|
||||
*/
|
||||
@Override
|
||||
public String getErrorStackTrace() {
|
||||
return "No error stack traces available at this level. Drill down to individual tests to find stack traces.";
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the text from the message.
|
||||
*/
|
||||
@Override
|
||||
public String getErrorDetails() {
|
||||
return "No error details available at this level. Drill down to individual tests to find details.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the test was not skipped and did not fail, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPassed() {
|
||||
return (getFailCount() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PackageResult> getChildren() {
|
||||
return byPackages.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this test result has children.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasChildren() {
|
||||
return !suites.isEmpty();
|
||||
}
|
||||
|
||||
@Exported(inline=true,visibility=9)
|
||||
public Collection<SuiteResult> getSuites() {
|
||||
return suites;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "junit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
|
||||
if (token.equals(getId())) {
|
||||
return this;
|
||||
}
|
||||
|
||||
PackageResult result = byPackage(token);
|
||||
if (result != null) {
|
||||
return result;
|
||||
} else {
|
||||
return super.getDynamic(token, req, rsp);
|
||||
}
|
||||
}
|
||||
|
||||
public PackageResult byPackage(String packageName) {
|
||||
return byPackages.get(packageName);
|
||||
}
|
||||
|
||||
public SuiteResult getSuite(String name) {
|
||||
return suitesByName.get(name);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recount my children.
|
||||
*/
|
||||
@Override
|
||||
public void tally() {
|
||||
/// Empty out data structures
|
||||
// TODO: free children? memmory leak?
|
||||
suitesByName = new HashMap<String,SuiteResult>();
|
||||
failedTests = new ArrayList<CaseResult>();
|
||||
byPackages = new TreeMap<String,PackageResult>();
|
||||
|
||||
totalTests = 0;
|
||||
skippedTests = 0;
|
||||
|
||||
// Ask all of our children to tally themselves
|
||||
for (SuiteResult s : suites) {
|
||||
s.setParent(this); // kluge to prevent double-counting the results
|
||||
suitesByName.put(s.getName(),s);
|
||||
List<CaseResult> cases = s.getCases();
|
||||
|
||||
for (CaseResult cr: cases) {
|
||||
cr.setParentAction(this.parentAction);
|
||||
cr.setParentSuiteResult(s);
|
||||
cr.tally();
|
||||
String pkg = cr.getPackageName(), spkg = safe(pkg);
|
||||
PackageResult pr = byPackage(spkg);
|
||||
if(pr==null)
|
||||
byPackages.put(spkg,pr=new PackageResult(this,pkg));
|
||||
pr.add(cr);
|
||||
}
|
||||
}
|
||||
|
||||
for (PackageResult pr : byPackages.values()) {
|
||||
pr.tally();
|
||||
skippedTests += pr.getSkipCount();
|
||||
failedTests.addAll(pr.getFailedTests());
|
||||
totalTests += pr.getTotalCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up the transient part of the data structure
|
||||
* from results {@link #parse(File) parsed} so far.
|
||||
*
|
||||
* <p>
|
||||
* After the data is frozen, more files can be parsed
|
||||
* and then freeze can be called again.
|
||||
*/
|
||||
public void freeze(TestResultAction parent) {
|
||||
this.parentAction = parent;
|
||||
if(suitesByName==null) {
|
||||
// freeze for the first time
|
||||
suitesByName = new HashMap<String,SuiteResult>();
|
||||
totalTests = 0;
|
||||
failedTests = new ArrayList<CaseResult>();
|
||||
byPackages = new TreeMap<String,PackageResult>();
|
||||
}
|
||||
|
||||
for (SuiteResult s : suites) {
|
||||
if(!s.freeze(this)) // this is disturbing: has-a-parent is conflated with has-been-counted
|
||||
continue;
|
||||
|
||||
suitesByName.put(s.getName(),s);
|
||||
|
||||
totalTests += s.getCases().size();
|
||||
for(CaseResult cr : s.getCases()) {
|
||||
if(cr.isSkipped())
|
||||
skippedTests++;
|
||||
else if(!cr.isPassed())
|
||||
failedTests.add(cr);
|
||||
|
||||
String pkg = cr.getPackageName(), spkg = safe(pkg);
|
||||
PackageResult pr = byPackage(spkg);
|
||||
if(pr==null)
|
||||
byPackages.put(spkg,pr=new PackageResult(this,pkg));
|
||||
pr.add(cr);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(failedTests,CaseResult.BY_AGE);
|
||||
|
||||
for (PackageResult pr : byPackages.values())
|
||||
pr.freeze();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import hudson.XmlFile;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Action;
|
||||
import hudson.model.BuildListener;
|
||||
import hudson.tasks.test.AbstractTestResultAction;
|
||||
import hudson.tasks.test.TestObject;
|
||||
import hudson.util.HeapSpaceStringConverter;
|
||||
import hudson.util.XStream2;
|
||||
import org.kohsuke.stapler.StaplerProxy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* {@link Action} that displays the JUnit test result.
|
||||
*
|
||||
* <p>
|
||||
* The actual test reports are isolated by {@link WeakReference}
|
||||
* so that it doesn't eat up too much memory.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class TestResultAction extends AbstractTestResultAction<TestResultAction> implements StaplerProxy {
|
||||
private transient WeakReference<TestResult> result;
|
||||
|
||||
// Hudson < 1.25 didn't set these fields, so use Integer
|
||||
// so that we can distinguish between 0 tests vs not-computed-yet.
|
||||
private int failCount;
|
||||
private int skipCount;
|
||||
private Integer totalCount;
|
||||
private Double healthScaleFactor;
|
||||
private List<Data> testData = new ArrayList<Data>();
|
||||
|
||||
@Deprecated
|
||||
public TestResultAction(AbstractBuild owner, TestResult result, BuildListener listener) {
|
||||
super(owner);
|
||||
setResult(result, listener);
|
||||
}
|
||||
|
||||
/** @since 1.545 */
|
||||
public TestResultAction(TestResult result, BuildListener listener) {
|
||||
this(null, result, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the {@link TestResult} by a new data set.
|
||||
*/
|
||||
public synchronized void setResult(TestResult result, BuildListener listener) {
|
||||
result.freeze(this);
|
||||
|
||||
totalCount = result.getTotalCount();
|
||||
failCount = result.getFailCount();
|
||||
skipCount = result.getSkipCount();
|
||||
|
||||
// persist the data
|
||||
try {
|
||||
getDataFile().write(result);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(listener.fatalError("Failed to save the JUnit test result"));
|
||||
}
|
||||
|
||||
this.result = new WeakReference<TestResult>(result);
|
||||
}
|
||||
|
||||
private XmlFile getDataFile() {
|
||||
return new XmlFile(XSTREAM,new File(owner.getRootDir(), "junitResult.xml"));
|
||||
}
|
||||
|
||||
public synchronized TestResult getResult() {
|
||||
TestResult r;
|
||||
if(result==null) {
|
||||
r = load();
|
||||
result = new WeakReference<TestResult>(r);
|
||||
} else {
|
||||
r = result.get();
|
||||
}
|
||||
|
||||
if(r==null) {
|
||||
r = load();
|
||||
result = new WeakReference<TestResult>(r);
|
||||
}
|
||||
if(totalCount==null) {
|
||||
totalCount = r.getTotalCount();
|
||||
failCount = r.getFailCount();
|
||||
skipCount = r.getSkipCount();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFailCount() {
|
||||
if(totalCount==null)
|
||||
getResult(); // this will compute the result
|
||||
return failCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
if(totalCount==null)
|
||||
getResult(); // this will compute the result
|
||||
return skipCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
if(totalCount==null)
|
||||
getResult(); // this will compute the result
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHealthScaleFactor() {
|
||||
return healthScaleFactor == null ? 1.0 : healthScaleFactor;
|
||||
}
|
||||
|
||||
public void setHealthScaleFactor(double healthScaleFactor) {
|
||||
this.healthScaleFactor = Math.max(0.0,healthScaleFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CaseResult> getFailedTests() {
|
||||
return getResult().getFailedTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link TestResult} from disk.
|
||||
*/
|
||||
private TestResult load() {
|
||||
TestResult r;
|
||||
try {
|
||||
r = (TestResult)getDataFile().read();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.WARNING, "Failed to load "+getDataFile(),e);
|
||||
r = new TestResult(); // return a dummy
|
||||
}
|
||||
r.freeze(this);
|
||||
return r;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return getResult();
|
||||
}
|
||||
|
||||
public List<TestAction> getActions(TestObject object) {
|
||||
List<TestAction> result = new ArrayList<TestAction>();
|
||||
// Added check for null testData to avoid NPE from issue 4257.
|
||||
if (testData != null) {
|
||||
for (Data data : testData)
|
||||
for (TestAction ta : data.getTestAction(object))
|
||||
if (ta != null)
|
||||
result.add(ta);
|
||||
}
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
public void setData(List<Data> testData) {
|
||||
this.testData = testData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves {@link TestAction}s for the given {@link TestObject}.
|
||||
*
|
||||
* <p>
|
||||
* This object itself is persisted as a part of {@link AbstractBuild}, so it needs to be XStream-serializable.
|
||||
*
|
||||
* @see TestDataPublisher
|
||||
*/
|
||||
public static abstract 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<? extends TestAction> getTestAction(hudson.tasks.junit.TestObject testObject);
|
||||
}
|
||||
|
||||
public Object readResolve() {
|
||||
super.readResolve(); // let it do the post-deserialization work
|
||||
if (testData == null) {
|
||||
testData = new ArrayList<Data>(0);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TestResultAction.class.getName());
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jorg Heymans
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.junit;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.tasks.junit.SuiteResult.SuiteResultParserConfigurationContext;
|
||||
import hudson.util.io.ParserConfigurator;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* As the name suggest: a resolver for XML entities.
|
||||
*
|
||||
* <p>
|
||||
* Basically, it provides the possibility to intercept online DTD lookups
|
||||
* and instead do offline lookup by redirecting to a local directory where
|
||||
* .dtd's are stored
|
||||
*
|
||||
* (useful when parsing testng-results.xml - which points to testng.org)
|
||||
*
|
||||
* @author Mikael Carneholm
|
||||
*/
|
||||
@Extension
|
||||
public class XMLEntityResolver extends ParserConfigurator implements EntityResolver {
|
||||
|
||||
private static final String TESTNG_NAMESPACE = "http://testng.org/";
|
||||
|
||||
/**
|
||||
* Intercepts the lookup of publicId, systemId
|
||||
*/
|
||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
||||
if (systemId != null) {
|
||||
if (LOGGER.isLoggable(Level.FINE)) {
|
||||
LOGGER.fine("Will try to resolve systemId [" + systemId + "]");
|
||||
}
|
||||
// TestNG system-ids
|
||||
if (systemId.startsWith(TESTNG_NAMESPACE)) {
|
||||
LOGGER.fine("It's a TestNG document, will try to lookup DTD in classpath");
|
||||
String dtdFileName = systemId.substring(TESTNG_NAMESPACE.length());
|
||||
|
||||
URL url = getClass().getClassLoader().getResource(dtdFileName);
|
||||
if (url != null)
|
||||
return new InputSource(url.toString());
|
||||
}
|
||||
}
|
||||
// Default fallback
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install EntityResolver for resolving DTDs, which are in files created by TestNG.
|
||||
*/
|
||||
@Override
|
||||
public void configure(SAXReader reader, Object context) {
|
||||
if (context instanceof SuiteResultParserConfigurationContext) {
|
||||
reader.setEntityResolver(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(XMLEntityResolver.class.getName());
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<html><head/><body>
|
||||
Model objects that represent JUnit test reports.
|
||||
</body></html>
|
|
@ -1,445 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.Functions;
|
||||
import hudson.model.*;
|
||||
import hudson.util.*;
|
||||
import hudson.util.ChartUtil.NumberOnlyBuildLabel;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import jenkins.model.RunAction2;
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.CategoryAxis;
|
||||
import org.jfree.chart.axis.CategoryLabelPositions;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.CategoryPlot;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.renderer.category.StackedAreaRenderer;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
import org.jvnet.localizer.Localizable;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
||||
/**
|
||||
* Common base class for recording test result.
|
||||
*
|
||||
* <p>
|
||||
* {@link Project} and {@link Build} recognizes {@link Action}s that derive from this,
|
||||
* and displays it nicely (regardless of the underlying implementation.)
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public abstract class AbstractTestResultAction<T extends AbstractTestResultAction> implements HealthReportingAction, RunAction2 {
|
||||
public transient AbstractBuild<?,?> owner;
|
||||
|
||||
private Map<String,String> descriptions = new ConcurrentHashMap<String, String>();
|
||||
|
||||
/** @since 1.545 */
|
||||
protected AbstractTestResultAction() {}
|
||||
|
||||
/** @deprecated Use the default constructor and just call {@link Run#addAction} to associate the build with the action. */
|
||||
@Deprecated
|
||||
protected AbstractTestResultAction(AbstractBuild owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override public void onAttached(Run<?, ?> r) {
|
||||
this.owner = (AbstractBuild<?,?>) r;
|
||||
}
|
||||
|
||||
@Override public void onLoad(Run<?, ?> r) {
|
||||
this.owner = (AbstractBuild<?,?>) r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of failed tests.
|
||||
*/
|
||||
@Exported(visibility=2)
|
||||
public abstract int getFailCount();
|
||||
|
||||
/**
|
||||
* Gets the number of skipped tests.
|
||||
*/
|
||||
@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
|
||||
// to implement it (this avoids breaking existing plug-ins - i.e. those
|
||||
// written before this method was added in 1.178).
|
||||
// Sub-classes that do support skipped tests should over-ride this method.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of tests.
|
||||
*/
|
||||
@Exported(visibility=2)
|
||||
public abstract int getTotalCount();
|
||||
|
||||
/**
|
||||
* Gets the diff string of failures.
|
||||
*/
|
||||
public final String getFailureDiffString() {
|
||||
T prev = getPreviousResult();
|
||||
if(prev==null) return ""; // no record
|
||||
|
||||
return " / "+Functions.getDiffString(this.getFailCount()-prev.getFailCount());
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return Messages.AbstractTestResultAction_getDisplayName();
|
||||
}
|
||||
|
||||
@Exported(visibility=2)
|
||||
public String getUrlName() {
|
||||
return "testReport";
|
||||
}
|
||||
|
||||
public String getIconFileName() {
|
||||
return "clipboard.png";
|
||||
}
|
||||
|
||||
public HealthReport getBuildHealth() {
|
||||
final double scaleFactor = getHealthScaleFactor();
|
||||
if (scaleFactor < 1e-7) {
|
||||
return null;
|
||||
}
|
||||
final int totalCount = getTotalCount();
|
||||
final int failCount = getFailCount();
|
||||
int score = (totalCount == 0)
|
||||
? 100
|
||||
: (int) (100.0 * Math.max(1.0, Math.min(0.0, 1.0 - (scaleFactor * failCount) / totalCount)));
|
||||
Localizable description, displayName = Messages._AbstractTestResultAction_getDisplayName();
|
||||
if (totalCount == 0) {
|
||||
description = Messages._AbstractTestResultAction_zeroTestDescription(displayName);
|
||||
} else {
|
||||
description = Messages._AbstractTestResultAction_TestsDescription(displayName, failCount, totalCount);
|
||||
}
|
||||
return new HealthReport(score, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how much to scale the test related health by.
|
||||
* @return a factor of {@code 1.0} to have the test health be the percentage of tests passing so 20% of tests
|
||||
* failing will report as 80% health. A factor of {@code 2.0} will mean that 20% of tests failing will report as 60%
|
||||
* health. A factor of {@code 2.5} will mean that 20% of test failing will report as 50% health. A factor of
|
||||
* {@code 4.0} will mean that 20% of tests failing will report as 20% health. A factor of {@code 5.0} will mean
|
||||
* that 20% (or more) of tests failing will report as 0% health. A factor of {@code 0.0} will disable test health
|
||||
* reporting.
|
||||
*/
|
||||
public double getHealthScaleFactor() {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes this object to the remote API.
|
||||
*/
|
||||
public Api getApi() {
|
||||
return new Api(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object that represents the actual test result.
|
||||
* This method is used by the remote API so that the XML/JSON
|
||||
* that we are sending won't contain unnecessary indirection
|
||||
* (that is, {@link AbstractTestResultAction} in between.
|
||||
*
|
||||
* <p>
|
||||
* If such a concept doesn't make sense for a particular subtype,
|
||||
* return <tt>this</tt>.
|
||||
*/
|
||||
public abstract Object getResult();
|
||||
|
||||
/**
|
||||
* Gets the test result of the previous build, if it's recorded, or null.
|
||||
*/
|
||||
public T getPreviousResult() {
|
||||
return (T)getPreviousResult(getClass(), true);
|
||||
}
|
||||
|
||||
private <U extends AbstractTestResultAction> U getPreviousResult(Class<U> type, boolean eager) {
|
||||
Set<Integer> loadedBuilds = eager ? null : owner.getProject()._getRuns().getLoadedBuilds().keySet();
|
||||
AbstractBuild<?,?> b = owner;
|
||||
while(true) {
|
||||
b = eager || 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)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public TestResult findPreviousCorresponding(TestResult test) {
|
||||
T previousResult = getPreviousResult();
|
||||
if (previousResult != null) {
|
||||
TestResult testResult = (TestResult)getResult();
|
||||
return testResult.findCorrespondingResult(test.getId());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TestResult findCorrespondingResult(String id) {
|
||||
return ((TestResult)getResult()).findCorrespondingResult(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for summary.jelly
|
||||
*
|
||||
* @return List of failed tests from associated test result.
|
||||
*/
|
||||
public List<? extends TestResult> getFailedTests() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a PNG image for the test result trend.
|
||||
*/
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
if(req.checkIfModified(owner.getTimestamp(),rsp))
|
||||
return;
|
||||
|
||||
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(owner.getTimestamp(),rsp))
|
||||
return;
|
||||
ChartUtil.generateClickableMap(req,rsp,createChart(req,buildDataSet(req)),calcDefaultSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full path down to a test result
|
||||
*/
|
||||
public String getTestResultPath(TestResult it) {
|
||||
return getUrlName() + "/" + it.getRelativePathFrom(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the default size of the trend graph.
|
||||
*
|
||||
* This is default because the query parameter can choose arbitrary size.
|
||||
* If the screen resolution is too low, use a smaller size.
|
||||
*/
|
||||
private Area calcDefaultSize() {
|
||||
Area res = Functions.getScreenResolution();
|
||||
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.valueOf(req.getParameter("failureOnly"));
|
||||
|
||||
DataSetBuilder<String,NumberOnlyBuildLabel> dsb = new DataSetBuilder<String,NumberOnlyBuildLabel>();
|
||||
|
||||
for (AbstractTestResultAction<?> a = this; a != null; a = a.getPreviousResult(AbstractTestResultAction.class, false)) {
|
||||
dsb.add( a.getFailCount(), "failed", new NumberOnlyBuildLabel(a.owner));
|
||||
if(!failureOnly) {
|
||||
dsb.add( a.getSkipCount(), "skipped", new NumberOnlyBuildLabel(a.owner));
|
||||
dsb.add( a.getTotalCount()-a.getFailCount()-a.getSkipCount(),"total", new NumberOnlyBuildLabel(a.owner));
|
||||
}
|
||||
}
|
||||
return dsb.build();
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
// 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);
|
||||
|
||||
chart.setBackgroundPaint(Color.white);
|
||||
|
||||
final CategoryPlot plot = chart.getCategoryPlot();
|
||||
|
||||
// plot.setAxisOffset(new Spacer(Spacer.ABSOLUTE, 5.0, 5.0, 5.0, 5.0));
|
||||
plot.setBackgroundPaint(Color.WHITE);
|
||||
plot.setOutlinePaint(null);
|
||||
plot.setForegroundAlpha(0.8f);
|
||||
// plot.setDomainGridlinesVisible(true);
|
||||
// plot.setDomainGridlinePaint(Color.white);
|
||||
plot.setRangeGridlinesVisible(true);
|
||||
plot.setRangeGridlinePaint(Color.black);
|
||||
|
||||
CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
|
||||
plot.setDomainAxis(domainAxis);
|
||||
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
|
||||
domainAxis.setLowerMargin(0.0);
|
||||
domainAxis.setUpperMargin(0.0);
|
||||
domainAxis.setCategoryMargin(0.0);
|
||||
|
||||
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
|
||||
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
|
||||
StackedAreaRenderer ar = new StackedAreaRenderer2() {
|
||||
@Override
|
||||
public String generateURL(CategoryDataset dataset, int row, int column) {
|
||||
NumberOnlyBuildLabel label = (NumberOnlyBuildLabel) dataset.getColumnKey(column);
|
||||
return relPath+label.build.getNumber()+"/testReport/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateToolTip(CategoryDataset dataset, int row, int column) {
|
||||
NumberOnlyBuildLabel label = (NumberOnlyBuildLabel) dataset.getColumnKey(column);
|
||||
AbstractTestResultAction a = label.build.getAction(AbstractTestResultAction.class);
|
||||
switch (row) {
|
||||
case 0:
|
||||
return String.valueOf(Messages.AbstractTestResultAction_fail(label.build.getDisplayName(), a.getFailCount()));
|
||||
case 1:
|
||||
return String.valueOf(Messages.AbstractTestResultAction_skip(label.build.getDisplayName(), a.getSkipCount()));
|
||||
default:
|
||||
return String.valueOf(Messages.AbstractTestResultAction_test(label.build.getDisplayName(), a.getTotalCount()));
|
||||
}
|
||||
}
|
||||
};
|
||||
plot.setRenderer(ar);
|
||||
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));
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
private String getRelPath(StaplerRequest req) {
|
||||
String relPath = req.getParameter("rel");
|
||||
if(relPath==null) return "";
|
||||
return relPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TestObject}s do not have their own persistence mechanism, so updatable data of {@link TestObject}s
|
||||
* need to be persisted by the owning {@link AbstractTestResultAction}, and this method and
|
||||
* {@link #setDescription(TestObject, String)} provides that logic.
|
||||
*
|
||||
* <p>
|
||||
* The default implementation stores information in the 'this' object.
|
||||
*
|
||||
* @see TestObject#getDescription()
|
||||
*/
|
||||
protected String getDescription(TestObject object) {
|
||||
return descriptions.get(object.getId());
|
||||
}
|
||||
|
||||
protected void setDescription(TestObject object, String description) {
|
||||
descriptions.put(object.getId(), description);
|
||||
}
|
||||
|
||||
public Object readResolve() {
|
||||
if (descriptions == null) {
|
||||
descriptions = new ConcurrentHashMap<String, String>();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
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()));
|
||||
}
|
||||
} else {
|
||||
if (trN.getFailCount() != 0) {
|
||||
if (trP.getFailCount() == 0) {
|
||||
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()));
|
||||
}
|
||||
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_TestsStillFailing(trN.getFailCount()));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link AbstractTestResultAction} that aggregates all the test results
|
||||
* from the corresponding {@link AbstractBuild}s.
|
||||
*
|
||||
* <p>
|
||||
* (This has nothing to do with {@link AggregatedTestResultPublisher}, unfortunately)
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public abstract class AggregatedTestResultAction extends AbstractTestResultAction {
|
||||
private int failCount,skipCount,totalCount;
|
||||
|
||||
public static final class Child {
|
||||
/**
|
||||
* Name of the module. Could be relative to something.
|
||||
* The interpretation of this is done by
|
||||
* {@link AggregatedTestResultAction#getChildName(AbstractTestResultAction)} and
|
||||
* {@link AggregatedTestResultAction#resolveChild(Child)} and
|
||||
*/
|
||||
public final String name;
|
||||
public final int build;
|
||||
|
||||
public Child(String name, int build) {
|
||||
this.name = name;
|
||||
this.build = build;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* child builds whose test results are used for aggregation.
|
||||
*/
|
||||
public final List<Child> children = new ArrayList<Child>();
|
||||
|
||||
@Deprecated
|
||||
public AggregatedTestResultAction(AbstractBuild owner) {
|
||||
super(owner);
|
||||
}
|
||||
|
||||
/** @since 1.545 */
|
||||
public AggregatedTestResultAction() {}
|
||||
|
||||
protected void update(List<? extends AbstractTestResultAction> children) {
|
||||
failCount = skipCount = totalCount = 0;
|
||||
this.children.clear();
|
||||
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.owner.number));
|
||||
}
|
||||
|
||||
public int getFailCount() {
|
||||
return failCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
return skipCount;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public List<ChildReport> getResult() {
|
||||
// I think this is a reasonable default.
|
||||
return getChildReports();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends TestResult> getFailedTests() {
|
||||
List<TestResult> failedTests = new ArrayList<TestResult>(failCount);
|
||||
for (ChildReport childReport : getChildReports()) {
|
||||
if (childReport.result instanceof TestResult) {
|
||||
failedTests.addAll(((TestResult) childReport.result).getFailedTests());
|
||||
}
|
||||
}
|
||||
return failedTests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data-binding bean for the remote API.
|
||||
*/
|
||||
@ExportedBean(defaultVisibility=2)
|
||||
public static final class ChildReport {
|
||||
@Exported
|
||||
public final AbstractBuild<?,?> child;
|
||||
@Exported
|
||||
public final Object result;
|
||||
|
||||
public ChildReport(AbstractBuild<?, ?> child, AbstractTestResultAction result) {
|
||||
this.child = child;
|
||||
this.result = result!=null ? result.getResult() : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mainly for the remote API. Expose results from children.
|
||||
*/
|
||||
@Exported(inline=true)
|
||||
public List<ChildReport> getChildReports() {
|
||||
return new AbstractList<ChildReport>() {
|
||||
public ChildReport get(int index) {
|
||||
return new ChildReport(
|
||||
resolveChild(children.get(index)),
|
||||
getChildReport(children.get(index)));
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return children.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract String getChildName(AbstractTestResultAction tr);
|
||||
public abstract AbstractBuild<?,?> resolveChild(Child child);
|
||||
|
||||
/**
|
||||
* Uses {@link #resolveChild(Child)} and obtain the
|
||||
* {@link AbstractTestResultAction} object for the given child.
|
||||
*/
|
||||
protected AbstractTestResultAction getChildReport(Child child) {
|
||||
AbstractBuild<?,?> b = resolveChild(child);
|
||||
if(b==null) return null;
|
||||
return b.getAction(AbstractTestResultAction.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since there's no TestObject that points this action as the owner
|
||||
* (aggregated {@link TestObject}s point to their respective real owners, not 'this'),
|
||||
* so this method should be never invoked.
|
||||
*
|
||||
* @deprecated
|
||||
* so that IDE warns you if you accidentally try to call it.
|
||||
*/
|
||||
@Override
|
||||
protected final String getDescription(TestObject object) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #getDescription(TestObject)}
|
||||
*
|
||||
* @deprecated
|
||||
* so that IDE warns you if you accidentally try to call it.
|
||||
*/
|
||||
@Override
|
||||
protected final void setDescription(TestObject object, String description) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
|
@ -1,378 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.AutoCompletionCandidates;
|
||||
import hudson.Extension;
|
||||
import hudson.Launcher;
|
||||
import hudson.Util;
|
||||
import static hudson.Util.fixNull;
|
||||
import hudson.model.Action;
|
||||
import hudson.model.BuildListener;
|
||||
import hudson.model.Fingerprint.RangeSet;
|
||||
import hudson.model.InvisibleAction;
|
||||
import hudson.model.ItemGroup;
|
||||
import jenkins.model.Jenkins;
|
||||
import hudson.model.Item;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.Result;
|
||||
import hudson.model.Run;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.model.listeners.RunListener;
|
||||
import hudson.tasks.BuildStepDescriptor;
|
||||
import hudson.tasks.BuildStepMonitor;
|
||||
import hudson.tasks.Fingerprinter.FingerprintAction;
|
||||
import hudson.tasks.Publisher;
|
||||
import hudson.tasks.Recorder;
|
||||
import hudson.util.FormValidation;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.kohsuke.stapler.AncestorInPath;
|
||||
import org.kohsuke.stapler.QueryParameter;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.CheckForNull;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
|
||||
/**
|
||||
* Aggregates downstream test reports into a single consolidated report,
|
||||
* so that people can see the overall test results in one page
|
||||
* when tests are scattered across many different jobs.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class AggregatedTestResultPublisher extends Recorder {
|
||||
/**
|
||||
* Jobs to aggregate. Comma separated.
|
||||
* Null if triggering downstreams.
|
||||
*/
|
||||
public final String jobs;
|
||||
|
||||
/**
|
||||
* Should failed builds be included?
|
||||
*/
|
||||
public final boolean includeFailedBuilds;
|
||||
|
||||
public AggregatedTestResultPublisher(String jobs) {
|
||||
this(jobs, false);
|
||||
}
|
||||
|
||||
public AggregatedTestResultPublisher(String jobs, boolean includeFailedBuilds) {
|
||||
this.jobs = Util.fixEmptyAndTrim(jobs);
|
||||
this.includeFailedBuilds = includeFailedBuilds;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public BuildStepMonitor getRequiredMonitorService() {
|
||||
return BuildStepMonitor.NONE;
|
||||
}
|
||||
|
||||
@Override public Collection<? extends Action> getProjectActions(AbstractProject<?, ?> project) {
|
||||
return Collections.singleton(new TestResultProjectAction(project));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that serves the aggregated record.
|
||||
*
|
||||
* TODO: persist some information so that even when some of the individuals
|
||||
* are gone, we can still retain some useful information.
|
||||
*/
|
||||
public static final class TestResultAction extends AbstractTestResultAction {
|
||||
/**
|
||||
* Jobs to aggregate. Comma separated.
|
||||
* Null if doing downstream projects.
|
||||
*/
|
||||
private final @CheckForNull String jobs;
|
||||
|
||||
/**
|
||||
* Should failed builds be included?
|
||||
*/
|
||||
private final boolean includeFailedBuilds;
|
||||
|
||||
/**
|
||||
* The last time the fields of this object is computed from the rest.
|
||||
*/
|
||||
private transient long lastUpdated = 0;
|
||||
/**
|
||||
* When was the last time any build completed?
|
||||
*/
|
||||
private static long lastChanged = 0;
|
||||
|
||||
private transient int failCount;
|
||||
private transient int totalCount;
|
||||
private transient List<AbstractTestResultAction> individuals;
|
||||
/**
|
||||
* Projects that haven't run yet.
|
||||
*/
|
||||
private transient List<AbstractProject> didntRun;
|
||||
private transient List<AbstractProject> noFingerprints;
|
||||
|
||||
@SuppressWarnings("deprecation") // calls getProject in constructor, so needs owner immediately
|
||||
public TestResultAction(String jobs, boolean includeFailedBuilds, AbstractBuild<?,?> owner) {
|
||||
super(owner);
|
||||
this.includeFailedBuilds = includeFailedBuilds;
|
||||
|
||||
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(',');
|
||||
buf.append(p.getFullName());
|
||||
}
|
||||
jobs = buf.toString();
|
||||
}
|
||||
this.jobs = jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the jobs to be monitored.
|
||||
*/
|
||||
public Collection<AbstractProject> getJobs() {
|
||||
List<AbstractProject> r = new ArrayList<AbstractProject>();
|
||||
for (String job : Util.tokenize(jobs,",")) {
|
||||
AbstractProject j = Jenkins.getInstance().getItemByFullName(job.trim(), AbstractProject.class);
|
||||
if(j!=null)
|
||||
r.add(j);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public boolean getIncludeFailedBuilds() {
|
||||
return includeFailedBuilds;
|
||||
}
|
||||
|
||||
private AbstractProject<?,?> getProject() {
|
||||
return owner.getProject();
|
||||
}
|
||||
|
||||
public int getFailCount() {
|
||||
upToDateCheck();
|
||||
return failCount;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
upToDateCheck();
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
upToDateCheck();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since there's no TestObject that points this action as the owner
|
||||
* (aggregated {@link TestObject}s point to their respective real owners, not 'this'),
|
||||
* so this method should be never invoked.
|
||||
*
|
||||
* @deprecated
|
||||
* so that IDE warns you if you accidentally try to call it.
|
||||
*/
|
||||
@Override
|
||||
protected String getDescription(TestObject object) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #getDescription(TestObject)}
|
||||
*
|
||||
* @deprecated
|
||||
* so that IDE warns you if you accidentally try to call it.
|
||||
*/
|
||||
@Override
|
||||
protected void setDescription(TestObject object, String description) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the individual test results that are aggregated.
|
||||
*/
|
||||
public List<AbstractTestResultAction> getIndividuals() {
|
||||
upToDateCheck();
|
||||
return Collections.unmodifiableList(individuals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the downstream projects that haven't run yet, but
|
||||
* expected to produce test results.
|
||||
*/
|
||||
public List<AbstractProject> getDidntRun() {
|
||||
return Collections.unmodifiableList(didntRun);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the downstream projects that have available test results, but
|
||||
* do not appear to have fingerprinting enabled.
|
||||
*/
|
||||
public List<AbstractProject> getNoFingerprints() {
|
||||
return Collections.unmodifiableList(noFingerprints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the data fields are up to date.
|
||||
*/
|
||||
private synchronized void upToDateCheck() {
|
||||
// up to date check
|
||||
if(lastUpdated>lastChanged) return;
|
||||
lastUpdated = lastChanged+1;
|
||||
|
||||
int failCount = 0;
|
||||
int totalCount = 0;
|
||||
List<AbstractTestResultAction> individuals = new ArrayList<AbstractTestResultAction>();
|
||||
List<AbstractProject> didntRun = new ArrayList<AbstractProject>();
|
||||
List<AbstractProject> noFingerprints = new ArrayList<AbstractProject>();
|
||||
for (AbstractProject job : getJobs()) {
|
||||
RangeSet rs = owner.getDownstreamRelationship(job);
|
||||
if(rs.isEmpty()) {
|
||||
// is this job expected to produce a test result?
|
||||
Run b;
|
||||
if (includeFailedBuilds) {
|
||||
b = job.getLastBuild();
|
||||
} else {
|
||||
b = job.getLastSuccessfulBuild();
|
||||
}
|
||||
if(b!=null && b.getAction(AbstractTestResultAction.class)!=null) {
|
||||
if(b.getAction(FingerprintAction.class)!=null) {
|
||||
didntRun.add(job);
|
||||
} else {
|
||||
noFingerprints.add(job);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int n : rs.listNumbersReverse()) {
|
||||
Run b = job.getBuildByNumber(n);
|
||||
if(b==null) continue;
|
||||
Result targetResult;
|
||||
if (includeFailedBuilds) {
|
||||
targetResult = Result.FAILURE;
|
||||
} else {
|
||||
targetResult = Result.UNSTABLE;
|
||||
}
|
||||
|
||||
if(b.isBuilding() || 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.failCount = failCount;
|
||||
this.totalCount = totalCount;
|
||||
this.individuals = individuals;
|
||||
this.didntRun = didntRun;
|
||||
this.noFingerprints = noFingerprints;
|
||||
}
|
||||
|
||||
public boolean getHasFingerprintAction() {
|
||||
return this.owner.getAction(FingerprintAction.class)!=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Messages.AggregatedTestResultPublisher_Title();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlName() {
|
||||
return "aggregatedTestReport";
|
||||
}
|
||||
|
||||
@Extension
|
||||
public static class RunListenerImpl extends RunListener<Run> {
|
||||
@Override
|
||||
public void onCompleted(Run run, TaskListener listener) {
|
||||
lastChanged = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Extension
|
||||
public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
|
||||
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
|
||||
return true; // for all types
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return Messages.AggregatedTestResultPublisher_DisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpFile() {
|
||||
return "/help/tasks/aggregate-test/help.html";
|
||||
}
|
||||
|
||||
public FormValidation doCheck(@AncestorInPath AbstractProject project, @QueryParameter String value) {
|
||||
// Require CONFIGURE permission on this project
|
||||
if(!project.hasPermission(Item.CONFIGURE)) return FormValidation.ok();
|
||||
|
||||
for (String name : Util.tokenize(fixNull(value), ",")) {
|
||||
name = name.trim();
|
||||
if(Jenkins.getInstance().getItem(name,project)==null)
|
||||
return FormValidation.error(hudson.tasks.Messages.BuildTrigger_NoSuchProject(name,AbstractProject.findNearest(name).getName()));
|
||||
}
|
||||
|
||||
return FormValidation.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregatedTestResultPublisher newInstance(StaplerRequest req, JSONObject formData) throws FormException {
|
||||
JSONObject s = formData.getJSONObject("specify");
|
||||
if(s.isNullObject())
|
||||
return new AggregatedTestResultPublisher(null, req.getParameter("includeFailedBuilds") != null);
|
||||
else
|
||||
return new AggregatedTestResultPublisher(s.getString("jobs"), req.getParameter("includeFailedBuilds") != null);
|
||||
}
|
||||
|
||||
public AutoCompletionCandidates doAutoCompleteJobs(@QueryParameter String value, @AncestorInPath Item self, @AncestorInPath ItemGroup 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) {
|
||||
this.project = project;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.AbortException;
|
||||
import hudson.FilePath;
|
||||
import hudson.FilePath.FileCallable;
|
||||
import hudson.Launcher;
|
||||
import hudson.Util;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.remoting.VirtualChannel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default partial implementation of {@link TestResultParser} that handles GLOB dereferencing
|
||||
* and other checks for user errors, such as misconfigured GLOBs, up-to-date checks on test reports.
|
||||
*
|
||||
* <p>
|
||||
* The instance of the parser will be serialized to the node that performed the build and the parsing will be done
|
||||
* remotely on that slave.
|
||||
*
|
||||
* @since 1.343
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class DefaultTestResultParserImpl extends TestResultParser implements Serializable {
|
||||
/**
|
||||
* This method is executed on the slave that has the report files to parse test reports and builds {@link TestResult}.
|
||||
*
|
||||
* @param reportFiles
|
||||
* List of files to be parsed. Never be empty nor null.
|
||||
* @param launcher
|
||||
* Can be used to fork processes on the machine where the build is running. Never null.
|
||||
* @param listener
|
||||
* Use this to report progress and other problems. Never null.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* If the user cancels the build, it will be received as a thread interruption. Do not catch
|
||||
* it, and instead just forward that through the call stack.
|
||||
* @throws IOException
|
||||
* If you don't care about handling exceptions gracefully, you can just throw IOException
|
||||
* and let the default exception handling in Hudson takes care of it.
|
||||
* @throws AbortException
|
||||
* 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<File> reportFiles, Launcher launcher, TaskListener listener) throws InterruptedException, IOException;
|
||||
|
||||
@Override
|
||||
public TestResult parse(final String testResultLocations, final AbstractBuild build, final Launcher launcher, final TaskListener listener) throws InterruptedException, IOException {
|
||||
return build.getWorkspace().act(new FileCallable<TestResult>() {
|
||||
final boolean ignoreTimestampCheck = IGNORE_TIMESTAMP_CHECK; // so that the property can be set on the master
|
||||
final long buildTime = build.getTimestamp().getTimeInMillis();
|
||||
final long nowMaster = System.currentTimeMillis();
|
||||
|
||||
public TestResult invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException {
|
||||
final long nowSlave = System.currentTimeMillis();
|
||||
|
||||
// files older than this timestamp is considered stale
|
||||
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?");
|
||||
|
||||
// since dir is local, paths all point to the local files
|
||||
List<File> files = new ArrayList<File>(paths.length);
|
||||
for (FilePath path : paths) {
|
||||
File report = new File(path.getRemote());
|
||||
if (ignoreTimestampCheck || localBuildTime - 3000 /*error margin*/ < report.lastModified()) {
|
||||
// this file is created during this build
|
||||
files.add(report);
|
||||
}
|
||||
}
|
||||
|
||||
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())));
|
||||
}
|
||||
|
||||
return parse(files,launcher,listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final boolean IGNORE_TIMESTAMP_CHECK = Boolean.getBoolean(TestResultParser.class.getName()+".ignoreTimestampCheck");
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
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.
|
||||
* {@link TabulatedResult} whose immediate children
|
||||
* are other {@link TabulatedResult}s.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class MetaTabulatedResult extends TabulatedResult {
|
||||
|
||||
/**
|
||||
* All failed tests.
|
||||
*/
|
||||
public abstract Collection<? extends TestResult> getFailedTests();
|
||||
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.tasks.junit.TestAction;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
/**
|
||||
* The simplest possible case result, with no language ties.
|
||||
* Acts as if it passed, has no children, and has no failed or skipped tests.
|
||||
*/
|
||||
public class SimpleCaseResult extends TestResult {
|
||||
protected AbstractTestResultAction parentAction;
|
||||
protected final List<SimpleCaseResult> listOnlyContainingThisObject = new ArrayList<SimpleCaseResult>(1);
|
||||
protected float duration = 1.0f;
|
||||
private static final Logger LOGGER = Logger.getLogger(SimpleCaseResult.class.getName());
|
||||
|
||||
public SimpleCaseResult(float duration) {
|
||||
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.
|
||||
* @param parentAction
|
||||
*/
|
||||
@Override
|
||||
public void setParentAction(AbstractTestResultAction parentAction) {
|
||||
this.parentAction = parentAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractTestResultAction getParentAction() {
|
||||
return this.parentAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestObject getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestResult findCorrespondingResult(String id) {
|
||||
if (id.equals(getId())) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that failed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getFailedTests() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that passed
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getPassedTests() {
|
||||
return listOnlyContainingThisObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that were skipped
|
||||
*
|
||||
* @return the children of this test result, if any, or an empty list
|
||||
*/
|
||||
@Override
|
||||
public Collection<? extends TestResult> getSkippedTests() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's pretend that our trivial test result always passes.
|
||||
* @return always true
|
||||
*/
|
||||
@Override
|
||||
public boolean isPassed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the test was skipped or not.
|
||||
*
|
||||
* @return true if the test was not executed, false otherwise.
|
||||
*/
|
||||
public boolean isSkipped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff this test failed.
|
||||
*/
|
||||
public boolean isFailed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time took to run this test. In seconds.
|
||||
*/
|
||||
@Override
|
||||
public float getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this object.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Simple Case Result";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of passed tests.
|
||||
*/
|
||||
@Override
|
||||
public int getPassCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of failed tests.
|
||||
*/
|
||||
@Override
|
||||
public int getFailCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of skipped tests.
|
||||
*/
|
||||
@Override
|
||||
public int getSkipCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the human readable title of this result object.
|
||||
*/
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Simple Case Result"; //
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Simple Case Result";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractBuild<?,?> getOwner() {
|
||||
if (parentAction == null) {
|
||||
LOGGER.warning("in Trivial Test Result, parentAction is null, but getOwner() called");
|
||||
return null;
|
||||
}
|
||||
return parentAction.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TestAction> getTestActions() {
|
||||
return SimpleCaseResult.EMPTY_ACTION_LIST;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An empty list of actions, useful for tests
|
||||
*/
|
||||
public static final List<TestAction> EMPTY_ACTION_LIST = Collections.unmodifiableList(new ArrayList<TestAction>());
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Cumulated result of multiple tests.
|
||||
*
|
||||
* <p>
|
||||
* On top of {@link TestResult}, this class introduces a tree structure
|
||||
* of {@link TestResult}s.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class TabulatedResult extends TestResult {
|
||||
|
||||
/**
|
||||
* Gets the child test result objects.
|
||||
*
|
||||
* @see TestObject#getParent()
|
||||
*/
|
||||
public abstract Collection<? extends TestResult> getChildren();
|
||||
|
||||
public abstract boolean hasChildren();
|
||||
|
||||
public String getChildTitle() {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,433 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.Util;
|
||||
import hudson.Functions;
|
||||
import hudson.model.*;
|
||||
import hudson.tasks.junit.History;
|
||||
import hudson.tasks.junit.TestAction;
|
||||
import hudson.tasks.junit.TestResultAction;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import org.kohsuke.stapler.*;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public abstract class TestObject extends hudson.tasks.junit.TestObject {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(TestObject.class.getName());
|
||||
private volatile transient String id;
|
||||
|
||||
public abstract AbstractBuild<?, ?> getOwner();
|
||||
|
||||
/**
|
||||
* Reverse pointer of {@link TabulatedResult#getChildren()}.
|
||||
*/
|
||||
public abstract TestObject getParent();
|
||||
|
||||
@Override
|
||||
public final String getId() {
|
||||
if (id == null) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(getSafeName());
|
||||
|
||||
TestObject parent = getParent();
|
||||
if (parent != null) {
|
||||
String parentId = parent.getId();
|
||||
if ((parentId != null) && (parentId.length() > 0)) {
|
||||
buf.insert(0, '/');
|
||||
buf.insert(0, parent.getId());
|
||||
}
|
||||
}
|
||||
id = buf.toString();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns url relative to TestResult
|
||||
*/
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return '/' + getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top level test result data.
|
||||
*
|
||||
* @deprecated This method returns a JUnit specific class. Use
|
||||
* {@link #getTopLevelTestResult()} instead for a more general interface.
|
||||
*/
|
||||
@Override
|
||||
public hudson.tasks.junit.TestResult getTestResult() {
|
||||
TestObject parent = getParent();
|
||||
|
||||
return (parent == null ? null : getParent().getTestResult());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 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 <code>it</code>. If
|
||||
* <code>it</code> does not appear in the parent chain for this object, a
|
||||
* relative path from the server root will be returned.
|
||||
*
|
||||
* @return A relative path to this object, potentially from the top of the
|
||||
* Hudson object model
|
||||
*/
|
||||
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) {
|
||||
return ".";
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
TestObject next = 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) {
|
||||
cur = next;
|
||||
buf.insert(0,'/');
|
||||
buf.insert(0,cur.getSafeName());
|
||||
next = cur.getParent();
|
||||
}
|
||||
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) {
|
||||
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());
|
||||
|
||||
// Now the build
|
||||
AbstractBuild<?,?> myBuild = cur.getOwner();
|
||||
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());
|
||||
|
||||
// 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) {
|
||||
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.info("trying to get relative path, but it is not my ancestor, and we're not in a stapler request. Trying absolute hudson url...");
|
||||
String hudsonRootUrl = Jenkins.getInstance().getRootUrl();
|
||||
if (hudsonRootUrl==null||hudsonRootUrl.length()==0) {
|
||||
LOGGER.warning("Can't find anything like a decent hudson url. Punting, returning empty string.");
|
||||
return "";
|
||||
|
||||
}
|
||||
buf.insert(0, '/');
|
||||
buf.insert(0, hudsonRootUrl);
|
||||
}
|
||||
|
||||
LOGGER.info("Here's our relative path: " + buf.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method if they are
|
||||
* associated with a particular subclass of
|
||||
* AbstractTestResultAction.
|
||||
*
|
||||
* @return the test result action that connects this test result to a particular build
|
||||
*/
|
||||
@Override
|
||||
public AbstractTestResultAction getTestResultAction() {
|
||||
AbstractBuild<?, ?> owner = getOwner();
|
||||
if (owner != null) {
|
||||
return owner.getAction(AbstractTestResultAction.class);
|
||||
} else {
|
||||
LOGGER.warning("owner is null when trying to getTestResultAction.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all TestActions associated with this TestObject.
|
||||
*/
|
||||
@Override
|
||||
public List<TestAction> getTestActions() {
|
||||
AbstractTestResultAction atra = getTestResultAction();
|
||||
if ((atra != null) && (atra instanceof TestResultAction)) {
|
||||
TestResultAction tra = (TestResultAction) atra;
|
||||
return tra.getActions(this);
|
||||
} else {
|
||||
return new ArrayList<TestAction>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a test action of the class passed in.
|
||||
* @param klazz
|
||||
* @param <T> an instance of the class passed in
|
||||
*/
|
||||
@Override
|
||||
public <T> T getTestAction(Class<T> klazz) {
|
||||
for (TestAction action : getTestActions()) {
|
||||
if (klazz.isAssignableFrom(action.getClass())) {
|
||||
return klazz.cast(action);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the counterpart of this {@link TestResult} in the previous run.
|
||||
*
|
||||
* @return null if no such counter part exists.
|
||||
*/
|
||||
public abstract TestResult getPreviousResult();
|
||||
|
||||
/**
|
||||
* Gets the counterpart of this {@link TestResult} in the specified run.
|
||||
*
|
||||
* @return null if no such counter part exists.
|
||||
*/
|
||||
public abstract TestResult getResultInBuild(AbstractBuild<?, ?> build);
|
||||
|
||||
/**
|
||||
* Find the test result corresponding to the one identified by <code>id></code>
|
||||
* within this test result.
|
||||
*
|
||||
* @param id The path to the original test result
|
||||
* @return A corresponding test result, or null if there is no corresponding
|
||||
* result.
|
||||
*/
|
||||
public abstract TestResult findCorrespondingResult(String id);
|
||||
|
||||
/**
|
||||
* Time took to run this test. In seconds.
|
||||
*/
|
||||
public abstract float getDuration();
|
||||
|
||||
/**
|
||||
* Returns the string representation of the {@link #getDuration()}, in a
|
||||
* human readable format.
|
||||
*/
|
||||
@Override
|
||||
public String getDurationString() {
|
||||
return Util.getTimeSpanString((long) (getDuration() * 1000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
AbstractTestResultAction action = getTestResultAction();
|
||||
if (action != null) {
|
||||
return action.getDescription(this);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
AbstractTestResultAction action = getTestResultAction();
|
||||
if (action != null) {
|
||||
action.setDescription(this, description);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes this object through the remote API.
|
||||
*/
|
||||
@Override
|
||||
public Api getApi() {
|
||||
return new Api(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this object.
|
||||
*/
|
||||
@Override
|
||||
public/* abstract */ String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full name of this object.
|
||||
* @since 1.594
|
||||
*/
|
||||
public String getFullName() {
|
||||
StringBuilder sb = new StringBuilder(getName());
|
||||
if (getParent() != null) {
|
||||
sb.insert(0, " : ");
|
||||
sb.insert(0, getParent().getFullName());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the version of {@link #getName()} that's URL-safe.
|
||||
*/
|
||||
@Override
|
||||
public String getSafeName() {
|
||||
return safe(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSearchUrl() {
|
||||
return getSafeName();
|
||||
}
|
||||
|
||||
/**
|
||||
* #2988: uniquifies a {@link #getSafeName} amongst children of the parent.
|
||||
*/
|
||||
protected final String uniquifyName(Collection<? extends TestObject> siblings, String base) {
|
||||
synchronized (UNIQUIFIED_NAMES) {
|
||||
String uniquified = base;
|
||||
Map<TestObject,Void> taken = UNIQUIFIED_NAMES.get(base);
|
||||
if (taken == null) {
|
||||
taken = new WeakHashMap<TestObject,Void>();
|
||||
UNIQUIFIED_NAMES.put(base, taken);
|
||||
} else {
|
||||
Set<TestObject> similars = new HashSet<TestObject>(taken.keySet());
|
||||
similars.retainAll(new HashSet<TestObject>(siblings));
|
||||
if (!similars.isEmpty()) {
|
||||
uniquified = base + '_' + (similars.size() + 1);
|
||||
}
|
||||
}
|
||||
taken.put(this, null);
|
||||
return uniquified;
|
||||
}
|
||||
}
|
||||
private static final Map<String,Map<TestObject,Void>> UNIQUIFIED_NAMES = new MapMaker().makeMap();
|
||||
|
||||
/**
|
||||
* Replaces URL-unsafe characters.
|
||||
*/
|
||||
public static String safe(String s) {
|
||||
// this still seems to be a bit faster than a single replace with regexp
|
||||
return s.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
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of passed tests.
|
||||
*/
|
||||
public abstract int getPassCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of failed tests.
|
||||
*/
|
||||
public abstract int getFailCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of skipped tests.
|
||||
*/
|
||||
public abstract int getSkipCount();
|
||||
|
||||
/**
|
||||
* Gets the total number of tests.
|
||||
*/
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
return getPassCount() + getFailCount() + getSkipCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public History getHistory() {
|
||||
return new History(this);
|
||||
}
|
||||
|
||||
public Object getDynamic(String token, StaplerRequest req,
|
||||
StaplerResponse rsp) {
|
||||
for (Action a : getTestActions()) {
|
||||
if (a == null) {
|
||||
continue; // be defensive
|
||||
}
|
||||
String urlName = a.getUrlName();
|
||||
if (urlName == null) {
|
||||
continue;
|
||||
}
|
||||
if (urlName.equals(token)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized HttpResponse doSubmitDescription(
|
||||
@QueryParameter String description) throws IOException,
|
||||
ServletException {
|
||||
if (getOwner() == null) {
|
||||
LOGGER.severe("getOwner() is null, can't save description.");
|
||||
} else {
|
||||
getOwner().checkPermission(Run.UPDATE);
|
||||
setDescription(description);
|
||||
getOwner().save();
|
||||
}
|
||||
|
||||
return new HttpRedirect(".");
|
||||
}
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.tasks.junit.TestAction;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Run;
|
||||
import hudson.model.Result;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
|
||||
/**
|
||||
* A class that represents a general concept of a test result, without any
|
||||
* language or implementation specifics.
|
||||
* Subclasses must add @Exported annotation to the fields they want to export.
|
||||
*
|
||||
* @since 1.343
|
||||
*/
|
||||
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.
|
||||
* @param action
|
||||
*/
|
||||
public void setParentAction(AbstractTestResultAction action) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action that points to the top level test result includes
|
||||
* this test result.
|
||||
*/
|
||||
public AbstractTestResultAction getParentAction() {
|
||||
return getOwner().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.
|
||||
*/
|
||||
public void tally() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent test result
|
||||
* @param parent
|
||||
*/
|
||||
public void setParent(TestObject parent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the human readable title of this result object.
|
||||
*/
|
||||
public /* abstract */ String getTitle(){
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a build as unstable if there are failures. Otherwise, leave the
|
||||
* build result unchanged.
|
||||
*
|
||||
* @return {@link Result#UNSTABLE} if there are test failures, null otherwise.
|
||||
*
|
||||
*/
|
||||
public Result getBuildResult() {
|
||||
if (getFailCount() > 0) {
|
||||
return Result.UNSTABLE;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Time it took to run this test. In seconds.
|
||||
*/
|
||||
public /* abstract */ float getDuration() {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of passed tests.
|
||||
*/
|
||||
public /* abstract */ int getPassCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of failed tests.
|
||||
*/
|
||||
public /* abstract */ int getFailCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the total number of skipped tests.
|
||||
*/
|
||||
public /* abstract */ int getSkipCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the counter part of this {@link TestResult} in the previous run.
|
||||
*
|
||||
* @return null if no such counter part exists.
|
||||
*/
|
||||
public TestResult getPreviousResult() {
|
||||
AbstractBuild<?,?> b = getOwner();
|
||||
if (b == null) {
|
||||
return null;
|
||||
}
|
||||
while(true) {
|
||||
b = b.getPreviousBuild();
|
||||
if(b==null)
|
||||
return null;
|
||||
AbstractTestResultAction r = b.getAction(getParentAction().getClass());
|
||||
if(r!=null) {
|
||||
TestResult result = r.findCorrespondingResult(this.getId());
|
||||
if (result!=null)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the counter part of this {@link TestResult} in the specified run.
|
||||
*
|
||||
* @return null if no such counter part exists.
|
||||
*/
|
||||
public TestResult getResultInBuild(AbstractBuild<?,?> build) {
|
||||
AbstractTestResultAction tra = build.getAction(getParentAction().getClass());
|
||||
if (tra == null) {
|
||||
tra = build.getAction(AbstractTestResultAction.class);
|
||||
}
|
||||
return (tra == null) ? null : tra.findCorrespondingResult(this.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that failed
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
public Collection<? extends TestResult> getFailedTests() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that passed
|
||||
* @return the children of this test result, if any, or an empty collection
|
||||
*/
|
||||
public Collection<? extends TestResult> getPassedTests() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "children" of this test result that were skipped
|
||||
* @return the children of this test result, if any, or an empty list
|
||||
*/
|
||||
public Collection<? extends TestResult> getSkippedTests() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this test failed, then return the build number
|
||||
* when this test started failing.
|
||||
*/
|
||||
public int getFailedSince() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this test failed, then return the run
|
||||
* when this test started failing.
|
||||
*/
|
||||
public Run<?,?> getFailedSinceRun() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stdout of this test.
|
||||
*/
|
||||
public String getStdout() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* The stderr of this test.
|
||||
*/
|
||||
public String getStderr() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the stack trace, or otherwise null.
|
||||
*/
|
||||
public String getErrorStackTrace() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* If there was an error or a failure, this is the text from the message.
|
||||
*/
|
||||
public String getErrorDetails() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the test was not skipped and did not fail, false otherwise.
|
||||
*/
|
||||
public boolean isPassed() {
|
||||
return ((getSkipCount() == 0) && (getFailCount() == 0));
|
||||
}
|
||||
|
||||
public String toPrettyString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
sb.append("Name: ").append(this.getName()).append(", ");
|
||||
sb.append("Result: ").append(this.getBuildResult()).append(",\n");
|
||||
sb.append("Total Count: ").append(this.getTotalCount()).append(", ");
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotate some text -- what does this do?
|
||||
* @param text
|
||||
*/
|
||||
public String annotate(String text) {
|
||||
if (text == null)
|
||||
return null;
|
||||
text = text.replace("&", "&").replace("<", "<").replaceAll(
|
||||
"\\b(https?://[^\\s)>]+)", "<a href=\"$1\">$1</a>");
|
||||
|
||||
for (TestAction action: getTestActions()) {
|
||||
text = action.annotate(text);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.AbortException;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.Launcher;
|
||||
import hudson.model.AbstractBuild;
|
||||
import jenkins.model.Jenkins;
|
||||
import hudson.model.TaskListener;
|
||||
import hudson.tasks.Publisher;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Parses test result files and builds in-memory representation of it as {@link TestResult}.
|
||||
*
|
||||
* <p>
|
||||
* This extension point encapsulates the knowledge of a particular test report format and its parsing process,
|
||||
* thereby improving the pluggability of test result parsing; integration with a new test tool can be done
|
||||
* by just writing a parser, without writing a custom {@link Publisher}, and the test reports are displayed
|
||||
* with the default UI and recognized by the rest of Hudson as test reports.
|
||||
*
|
||||
* <p>
|
||||
* Most typical implementations of this class should extend from {@link DefaultTestResultParserImpl},
|
||||
* which handles a set of default error checks on user inputs.
|
||||
*
|
||||
* <p>
|
||||
* Parsers are stateless, and the {@link #parse(String, AbstractBuild, Launcher, TaskListener)} method
|
||||
* can be concurrently invoked by multiple threads for different builds.
|
||||
*
|
||||
* @since 1.343
|
||||
* @see DefaultTestResultParserImpl
|
||||
*/
|
||||
public abstract class TestResultParser implements ExtensionPoint {
|
||||
/**
|
||||
* Returns a human readable name of the parser, like "JUnit Parser".
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return "Unknown Parser";
|
||||
}
|
||||
|
||||
/**
|
||||
* This text is used in the UI prompt for the GLOB that specifies files to be parsed by this parser.
|
||||
* For example, "JUnit XML reports:"
|
||||
*/
|
||||
public String getTestResultLocationMessage() {
|
||||
return "Paths to results files to parse:";
|
||||
}
|
||||
|
||||
/**
|
||||
* All registered {@link TestResultParser}s
|
||||
*/
|
||||
public static ExtensionList<TestResultParser> all() {
|
||||
return ExtensionList.lookup(TestResultParser.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified set of files and builds a {@link TestResult} object that represents them.
|
||||
*
|
||||
* <p>
|
||||
* The implementation is encouraged to do the following:
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* If the build is successful but GLOB didn't match anything, report that as an error. This is
|
||||
* to detect the error in GLOB. But don't do this if the build has already failed (for example,
|
||||
* think of a failure in SCM checkout.)
|
||||
*
|
||||
* <li>
|
||||
* Examine time stamp of test report files and if those are younger than the build, ignore them.
|
||||
* This is to ignore test reports created by earlier executions. Take the possible timestamp
|
||||
* difference in the master/slave into account.
|
||||
* </ul>
|
||||
*
|
||||
* @param testResultLocations
|
||||
* GLOB pattern relative to the {@linkplain AbstractBuild#getWorkspace() workspace} that
|
||||
* specifies the locations of the test result files. Never null.
|
||||
* @param build
|
||||
* Build for which these tests are parsed. Never null.
|
||||
* @param launcher
|
||||
* Can be used to fork processes on the machine where the build is running. Never null.
|
||||
* @param listener
|
||||
* Use this to report progress and other problems. Never null.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* If the user cancels the build, it will be received as a thread interruption. Do not catch
|
||||
* it, and instead just forward that through the call stack.
|
||||
* @throws IOException
|
||||
* If you don't care about handling exceptions gracefully, you can just throw IOException
|
||||
* and let the default exception handling in Hudson takes care of it.
|
||||
* @throws AbortException
|
||||
* If you encounter an error that you handled gracefully, throw this exception and Hudson
|
||||
* will not show a stack trace.
|
||||
*/
|
||||
public abstract TestResult parse(String testResultLocations,
|
||||
AbstractBuild build, Launcher launcher,
|
||||
TaskListener listener)
|
||||
throws InterruptedException, IOException;
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
|
||||
*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package hudson.tasks.test;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Action;
|
||||
import hudson.tasks.junit.JUnitResultArchiver;
|
||||
import org.kohsuke.stapler.Ancestor;
|
||||
import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Project action object from test reporter, such as {@link JUnitResultArchiver},
|
||||
* which displays the trend report on the project top page.
|
||||
*
|
||||
* <p>
|
||||
* This works with any {@link AbstractTestResultAction} implementation.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class TestResultProjectAction implements Action {
|
||||
/**
|
||||
* Project that owns this action.
|
||||
*/
|
||||
public final AbstractProject<?,?> project;
|
||||
|
||||
public TestResultProjectAction(AbstractProject<?,?> project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
/**
|
||||
* No task list item.
|
||||
*/
|
||||
public String getIconFileName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Test Report";
|
||||
}
|
||||
|
||||
public String getUrlName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
public AbstractTestResultAction getLastTestResultAction() {
|
||||
final AbstractBuild<?,?> tb = project.getLastSuccessfulBuild();
|
||||
|
||||
AbstractBuild<?,?> b=project.getLastBuild();
|
||||
while(b!=null) {
|
||||
AbstractTestResultAction a = b.getAction(AbstractTestResultAction.class);
|
||||
if(a!=null && (!b.isBuilding())) return a;
|
||||
if(b==tb)
|
||||
// if even the last successful build didn't produce the test result,
|
||||
// that means we just don't have any tests configured.
|
||||
return null;
|
||||
b = b.getPreviousBuild();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the test result trend.
|
||||
*/
|
||||
public void doTrend( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
|
||||
AbstractTestResultAction a = getLastTestResultAction();
|
||||
if(a!=null)
|
||||
a.doGraph(req,rsp);
|
||||
else
|
||||
rsp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the clickable map HTML fragment for {@link #doTrend(StaplerRequest, StaplerResponse)}.
|
||||
*/
|
||||
public void doTrendMap( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
|
||||
AbstractTestResultAction a = getLastTestResultAction();
|
||||
if(a!=null)
|
||||
a.doGraphMap(req,rsp);
|
||||
else
|
||||
rsp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the test result report display mode.
|
||||
*/
|
||||
public void doFlipTrend( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
|
||||
boolean failureOnly = false;
|
||||
|
||||
// check the current preference value
|
||||
Cookie[] cookies = req.getCookies();
|
||||
if(cookies!=null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if(cookie.getName().equals(FAILURE_ONLY_COOKIE))
|
||||
failureOnly = Boolean.parseBoolean(cookie.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// flip!
|
||||
failureOnly = !failureOnly;
|
||||
|
||||
// set the updated value
|
||||
Cookie cookie = new Cookie(FAILURE_ONLY_COOKIE,String.valueOf(failureOnly));
|
||||
List anc = req.getAncestors();
|
||||
Ancestor a = (Ancestor) anc.get(anc.size()-2);
|
||||
cookie.setPath(a.getUrl()); // just for this project
|
||||
cookie.setMaxAge(60*60*24*365); // 1 year
|
||||
rsp.addCookie(cookie);
|
||||
|
||||
// back to the project page
|
||||
rsp.sendRedirect("..");
|
||||
}
|
||||
|
||||
private static final String FAILURE_ONLY_COOKIE = "TestResultAction_failureOnly";
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<html><head/><body>
|
||||
Defines contracts that need to be implemented by a test reporting
|
||||
action (such as the built-in JUnit one). This contract allows <tt>Project</tt>
|
||||
to display a test result trend history.
|
||||
</body></html>
|
|
@ -24,7 +24,6 @@
|
|||
package hudson.util;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.tasks.junit.History;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
|
@ -93,7 +92,7 @@ public class ChartUtil {
|
|||
* The size of the picture to be generated. These values can be overridden
|
||||
* by the query paramter 'width' and 'height' in the request.
|
||||
* @deprecated as of 1.320
|
||||
* Bind {@link Graph} to the URL space. See {@link History} as an example (note that doing so involves
|
||||
* Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves
|
||||
* a bit of URL structure change.)
|
||||
*/
|
||||
public static void generateGraph(StaplerRequest req, StaplerResponse rsp, JFreeChart chart, Area defaultSize) throws IOException {
|
||||
|
@ -108,7 +107,7 @@ public class ChartUtil {
|
|||
* The size of the picture to be generated. These values can be overridden
|
||||
* by the query paramter 'width' and 'height' in the request.
|
||||
* @deprecated as of 1.320
|
||||
* Bind {@link Graph} to the URL space. See {@link History} as an example (note that doing so involves
|
||||
* Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves
|
||||
* a bit of URL structure change.)
|
||||
*/
|
||||
public static void generateGraph(StaplerRequest req, StaplerResponse rsp, final JFreeChart chart, int defaultW, int defaultH) throws IOException {
|
||||
|
@ -123,7 +122,7 @@ public class ChartUtil {
|
|||
* Generates the clickable map info and sends that to the response.
|
||||
*
|
||||
* @deprecated as of 1.320
|
||||
* Bind {@link Graph} to the URL space. See {@link History} as an example (note that doing so involves
|
||||
* Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves
|
||||
* a bit of URL structure change.)
|
||||
*/
|
||||
public static void generateClickableMap(StaplerRequest req, StaplerResponse rsp, JFreeChart chart, Area defaultSize) throws IOException {
|
||||
|
@ -134,7 +133,7 @@ public class ChartUtil {
|
|||
* Generates the clickable map info and sends that to the response.
|
||||
*
|
||||
* @deprecated as of 1.320
|
||||
* Bind {@link Graph} to the URL space. See {@link History} as an example (note that doing so involves
|
||||
* Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves
|
||||
* a bit of URL structure change.)
|
||||
*/
|
||||
public static void generateClickableMap(StaplerRequest req, StaplerResponse rsp, final JFreeChart chart, int defaultW, int defaultH) throws IOException {
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Daniel Dyer, Seiji Sogabe, Tom Huybrechts
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
|
||||
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<l:layout title="${it.owner} test - ${it.displayName}">
|
||||
<st:include page="sidepanel.jelly" />
|
||||
<l:main-panel>
|
||||
<j:set var="st" value="${it.status}" />
|
||||
<h1 class="${st.cssClass}">
|
||||
<st:out value="${st.message}" />
|
||||
</h1>
|
||||
<p>
|
||||
<span style="font-weight:bold">
|
||||
<st:out value="${it.fullDisplayName}"/>
|
||||
</span>
|
||||
<j:if test="${it.suiteResult != null && it.className != it.suiteResult.name}">
|
||||
(from <st:out value="${it.suiteResult.name}"/>)
|
||||
</j:if>
|
||||
</p>
|
||||
<j:if test="${!it.passed}">
|
||||
<div style="text-align:right;">
|
||||
<j:choose>
|
||||
<j:when test="${it.skipped}">
|
||||
${%skippedFor(it.age)}
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
${%failingFor(it.age)}
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
(${%since.before}<t:buildLink job="${it.owner.project}" number="${it.failedSince}"/>${%since.after})
|
||||
</div>
|
||||
</j:if>
|
||||
|
||||
<div style="text-align:right;">
|
||||
<a href="history">
|
||||
${%took(it.durationString)}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<t:editableDescription permission="${it.owner.UPDATE}"/>
|
||||
|
||||
<table style="margin-top: 1em; margin-left:0em;">
|
||||
<j:forEach var="action" items="${it.testActions}">
|
||||
<st:include page="summary.jelly" from="${action}" optional="true" it="${action}" />
|
||||
</j:forEach>
|
||||
</table>
|
||||
|
||||
<j:if test="${!empty(it.skippedMessage)}">
|
||||
<h3>${%Skip Message}</h3>
|
||||
<pre><j:out value="${it.annotate(it.skippedMessage)}"/></pre>
|
||||
</j:if>
|
||||
|
||||
<j:if test="${!empty(it.errorDetails)}">
|
||||
<h3>${%Error Message}</h3>
|
||||
<pre><j:out value="${it.annotate(it.errorDetails)}"/></pre>
|
||||
</j:if>
|
||||
|
||||
<j:if test="${!empty(it.errorStackTrace)}">
|
||||
<h3>${%Stacktrace}</h3>
|
||||
<pre><j:out value="${it.annotate(it.errorStackTrace)}"/></pre>
|
||||
</j:if>
|
||||
|
||||
<j:if test="${!empty(it.stdout)}">
|
||||
<h3>${%Standard Output}</h3>
|
||||
<pre><j:out value="${it.annotate(it.stdout)}"/></pre>
|
||||
</j:if>
|
||||
|
||||
<j:if test="${!empty(it.stderr)}">
|
||||
<h3>${%Standard Error}</h3>
|
||||
<pre><j:out value="${it.annotate(it.stderr)}"/></pre>
|
||||
</j:if>
|
||||
</l:main-panel>
|
||||
</l:layout>
|
||||
</j:jelly>
|
|
@ -1,27 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
failingFor=Failing for the past {0} {0,choice,0#builds|1#build|1<builds}
|
||||
skippedFor=Skipped for the past {0} {0,choice,0#builds|1#build|1<builds}
|
||||
took=Took {0}.
|
||||
since.before=Since' '
|
||||
since.after=' '
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
took=Tog {0}.
|
||||
Stacktrace=Stacktrace
|
||||
Error\ Message=Fejlbesked
|
||||
since.after=' '
|
||||
failingFor=Har fejlet {0,choice,0#de|1#det|1<de} seneste {0} byg
|
||||
skippedFor=Sprunget over {0,choice,0#de|1#det|1<de} seneste {0} byg
|
||||
Standard\ Error=Standard Error
|
||||
since.before=Siden' '
|
||||
Standard\ Output=Standard Output
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=Wird übersprungen seit {0} {0,choice,0#Builds|1#Build|1<Builds}
|
||||
failingFor=Schlägt fehl seit {0} {0,choice,0#Builds|1#Build|1<Builds}
|
||||
since.before=Seit' '
|
||||
since.after=' '
|
||||
took=Dauer: {0}.
|
||||
Standard\ Output=Standard Ausgabe (STDOUT)
|
||||
Standard\ Error=Standard Fehler (STDERR)
|
||||
Error\ Message=Fehlermeldung
|
||||
Stacktrace=Stacktrace
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
failingFor=Fallando durante los últimos {0} {0,choice,0#builds|1#build|1<builds}
|
||||
skippedFor=Omitidos durante los últimos {0} {0,choice,0#builds|1#build|1<builds}
|
||||
took=Tard\u00F3 {0}.
|
||||
since.before=Desde'' ''
|
||||
since.after='' ''
|
||||
Standard\ Error=Salida de error
|
||||
Error\ Message=Mensaje de error
|
||||
Stacktrace=Traza
|
||||
Standard\ Output=Salida estandard
|
|
@ -1,23 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
took=Vei {0}.
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=Build sauté depuis {0} {0,choice,0#build|1#build|1<builds}
|
||||
took=A duré {0}.
|
||||
since.before=Depuis' '
|
||||
since.after=' '
|
||||
Standard\ Output=Sortie standard
|
||||
Standard\ Error=Sortie d''erreur standard
|
||||
Error\ Message=Message d''erreur
|
||||
Stacktrace=Pile d''ex\u00E9cution
|
||||
failingFor=En échec depuis {0} {0,choice,0#build|1#build|1<builds}
|
|
@ -1,8 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Error\ Message=\u05D4\u05D5\u05D3\u05E2\u05EA \u05E9\u05D2\u05D9\u05D0\u05D4
|
||||
Standard\ Output=\u05E4\u05DC\u05D8 \u05E1\u05D8\u05E0\u05D3\u05E8\u05D8\u05D9
|
||||
failingFor=\u05E0\u05DB\u05E9\u05DC \u05DE\u05D0\u05D6 {0} {0,choice,0#\u05D1\u05E0\u05D9\u05D5\u05EA|1#\u05D4\u05D1\u05E0\u05D9\u05D4 \u05D4\u05D0\u05D7\u05E8\u05D5\u05E0\u05D4|1<\u05D1\u05E0\u05D9\u05D5\u05EA}
|
||||
since.after='' ''
|
||||
since.before=\u05D4\u05D7\u05DC \u05DE-'' ''
|
||||
took=\u05E0\u05DE\u05E9\u05DA {0}.
|
|
@ -1,5 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
failingFor=Hib\u00E1s az elm\u00FAlt {0} {0,choice,0#\u00E9p\u00EDt\u00E9s|1#\u00E9p\u00EDt\u00E9s|1<\u00E9p\u00EDt\u00E9s} \u00F3ta
|
||||
since.before=Kezdve'' ''
|
||||
took={0}-t vett ig\u00E9nybe.
|
|
@ -1,32 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=\u904e\u53bb {0}{0,choice,0#\u30d3\u30eb\u30c9|1#\u30d3\u30eb\u30c9|1<\u30d3\u30eb\u30c9} \u30b9\u30ad\u30c3\u30d7
|
||||
failingFor=\u904e\u53bb {0}{0,choice,0#\u30d3\u30eb\u30c9|1#\u30d3\u30eb\u30c9|1<\u30d3\u30eb\u30c9} \u5931\u6557
|
||||
since.before=' '
|
||||
since.after=' \u4ee5\u964d '
|
||||
took=\u6240\u8981\u6642\u9593 {0}
|
||||
Standard\ Output=\u6a19\u6e96\u51fa\u529b
|
||||
Standard\ Error=\u6a19\u6e96\u30a8\u30e9\u30fc\u51fa\u529b
|
||||
Error\ Message=\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8
|
||||
Stacktrace=\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9
|
||||
Skip\ Message=\u30b9\u30ad\u30c3\u30d7\u30e1\u30c3\u30bb\u30fc\u30b8
|
|
@ -1,5 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Error\ Message=Klaidos \u017Einut\u0117
|
||||
since.before=Nuo'' ''
|
||||
took=U\u017Etruko {0}.
|
|
@ -1,8 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Error\ Message=K\u013C\u016Bdas zi\u0146ojums
|
||||
Standard\ Output=Standarta Izvaddati
|
||||
failingFor=Izg\u0101\u017Eas p\u0113c p\u0113d\u0113jiem {0} {0,choice,0#builds|1#build|1<builds}
|
||||
since.after='' ''
|
||||
since.before=Kop\u0161'' ''
|
||||
took=Aiz\u0146\u0113ma {0}.
|
|
@ -1,29 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:sorokh
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=Overgeslagen voor de laatste {0} {0,choice,0#bouwpogingen|1#bouwpoging|1<bouwpogingen}
|
||||
failingFor=Gefaald voor de laatste {0} {0,choice,0#bouwpogingen|1#bouwpoging|1<bouwpogingen}
|
||||
since.before=sinds'' ''
|
||||
since.after=' '
|
||||
took=Duurde {0}.
|
||||
Standard\ Output=Standaard Output
|
||||
Standard\ Error=Standaard Fout
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
failingFor=Zawodzi od {0} {0,choice,0#uruchomie\u0144|1#uruchomienia|1<uruchomie\u0144}
|
||||
since.after=
|
||||
since.before=od
|
||||
took=Wykonano w {0}
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
failingFor=Falhando para {0} {0,choice,0#builds|1#build|1<builds}
|
||||
skippedFor=Pulou para {0} {0,choice,0#builds|1#build|1<builds}
|
||||
took=Levou {0}.
|
||||
since.before=Desde' '
|
||||
since.after=' '
|
||||
Standard\ Output=Sa\u00EDda padr\u00E3o
|
||||
Stacktrace=Pilha
|
||||
Standard\ Error=Sa\u00EDda de erro padr\u00E3o
|
||||
Error\ Message=Mensagem de erro
|
|
@ -1,31 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Mike Salnikov
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
failingFor={0,choice,0#\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435|1#\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f|1<\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435} {0} {0,choice,0#\u0441\u0431\u043e\u0440\u043e\u043a|1#\u0441\u0431\u043e\u0440\u043a\u0430|1<\u0441\u0431\u043e\u0440\u043a\u0438|4<\u0441\u0431\u043e\u0440\u043e\u043a} \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u043b\u0438\u0441\u044c
|
||||
skippedFor=\u041f\u0440\u043e\u043f\u0443\u0449\u0435\u043d\u044b \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 {0} {0,choice,0#\u0441\u0431\u043e\u0440\u043e\u043a|1#\u0441\u0431\u043e\u0440\u043a\u0430|1<\u0441\u0431\u043e\u0440\u043a\u0438|5<\u0441\u0431\u043e\u0440\u043e\u043a}
|
||||
took=\u0417\u0430\u043d\u044f\u043b\u043e {0}.
|
||||
since.before=\u0421' '
|
||||
since.after=' '
|
||||
Standard\ Output=\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434 (STDOUT)
|
||||
Error\ Message=\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E\u0431 \u043E\u0448\u0438\u0431\u043A\u0435
|
||||
Stacktrace=\u0421\u0442\u0435\u043A \u0432\u044B\u0437\u043E\u0432\u043E\u0432
|
||||
Standard\ Error=\u0412\u044b\u0432\u043e\u0434 \u043e\u0448\u0438\u0431\u043e\u043a (STDERR)
|
|
@ -1,29 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Message=Felmeddelande
|
||||
Stacktrace=Stacktrace
|
||||
failingFor=Har fallerat i {0,choice,0#de|1# |1<de} senaste {0} {0,choice,0#byggen|1#bygge|1<byggena}
|
||||
since.after='' ''
|
||||
since.before=Sedan'' ''
|
||||
skippedFor=Hoppat \u00F6ver f\u00F6r de senaste {0} {0,choice,0#builds|1#build|1<byggena}
|
||||
took=Tog {0}.
|
|
@ -1,29 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Oguz Dag
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=Son {0} i\u00e7erisinde es ge\u00e7ildi {0,choice,0#yap\u0131land\u0131rma|1#yap\u0131land\u0131rma|1<yap\u0131land\u0131rma}
|
||||
failingFor=Son {0} i\u00e7erisinde ba\u015far\u0131s\u0131z oldu {0,choice,0#yap\u0131land\u0131rma|1#yap\u0131land\u0131rma|1<yap\u0131land\u0131rma}
|
||||
since.before=' 'den beri
|
||||
since.after=' '
|
||||
took={0} s\u00fcrd\u00fc
|
||||
Standard\ Output=Standard \u00c7\u0131kt\u0131 (STDOUT)
|
||||
Standard\ Error=Standard Hata (STDERR)
|
|
@ -1,5 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
failingFor=\u041F\u043E\u043C\u0438\u043B\u043A\u0438 \u0432 \u043E\u0441\u0442\u0430\u043D\u043D\u0456\u0445 {0} {0,choice,0#builds|1#build|1<\u0441\u0431\u043E\u0440\u043A\u0430\u0445}
|
||||
since.before=\u043F\u043E\u0447\u0438\u043D\u0430\u044E\u0447\u0438 \u0437 '' ''
|
||||
took=\u0417\u0430\u0439\u043D\u044F\u043B\u043E {0}.
|
|
@ -1,3 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
took=\u8FD0\u884C\u65F6\u95F4\uFF1A{0}
|
|
@ -1,33 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2013, Sun Microsystems, Inc., Chunghwa Telecom Co., Ltd.,
|
||||
# and Pei-Tang Huang
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
skippedFor=\u6700\u8fd1 {0} \u6b21\u5efa\u7f6e\u90fd\u7565\u904e
|
||||
failingFor=\u9023\u7e8c {0} \u6b21\u5efa\u7f6e\u90fd\u5931\u6557
|
||||
since.before=\u5f9e' '
|
||||
since.after=' '\u958b\u59cb
|
||||
took=\u82b1\u8cbb {0}
|
||||
|
||||
Error\ Message=\u932f\u8aa4\u8a0a\u606f
|
||||
Stacktrace=\u5806\u758a\u8ffd\u8e64
|
||||
Standard\ Error=\u6a19\u6e96\u932f\u8aa4
|
||||
Standard\ Output=\u6a19\u6e96\u8f2a\u51fa
|
|
@ -1,62 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Trend of test execution over time.
|
||||
-->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
|
||||
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<table class="pane sortable bigtable" id="testresult">
|
||||
<tr>
|
||||
<td class="pane-header" style="width:10em">${%Build}</td>
|
||||
<td class="pane-header" style="width:10em">${%Test Description}</td>
|
||||
<td class="pane-header" style="width:5em">${%Test Duration}</td>
|
||||
<td class="pane-header" style="width:5em">${%Test Result}</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
<j:forEach var="b" items="${it.owner.parent.builds}" begin="${start}" end="${end}">
|
||||
<j:set var="test" value="${it.getResultInBuild(b)}"/>
|
||||
<j:if test="${test != null}">
|
||||
<tr>
|
||||
<td class="pane">
|
||||
<a href="${app.rootUrl}${b.url}testReport${p.url}" class="model-link inside">${b.fullDisplayName}</a>
|
||||
<j:forEach var="badge" items="${test.testActions}">
|
||||
<st:include it="${badge}" page="badge.jelly" optional="true"/>
|
||||
</j:forEach>
|
||||
</td>
|
||||
<td class="pane" style="text-align:left"><j:out value="${test.description}"/></td>
|
||||
<td class="pane" style="text-align:left" data="${test.duration}">${test.durationString}</td>
|
||||
<td class="pane">
|
||||
<j:set var="pst" value="${test.status}" />
|
||||
<span class="${pst.cssClass}">
|
||||
${pst.message}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</j:if>
|
||||
</j:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</j:jelly>
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Byg
|
||||
Test\ Result=Testresultat
|
||||
Test\ Description=Testbeskrivelse
|
||||
Test\ Duration=Testvarighed
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Build
|
||||
Test\ Description=Testbeschreibung
|
||||
Test\ Duration=Testdauer
|
||||
Test\ Result=Testergebnis
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Ejecución
|
||||
Test\ Description=Descripción del test
|
||||
Test\ Duration=Duración del test
|
||||
Test\ Result=Resultado del test
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Construction
|
||||
Test\ Description=Description
|
||||
Test\ Duration=Dur\u00E9e
|
||||
Test\ Result=R\u00E9sultat
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Seiji Sogabe
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=\u30D3\u30EB\u30C9
|
||||
Test\ Description=\u30C6\u30B9\u30C8\u306E\u8AAC\u660E
|
||||
Test\ Duration=\u30C6\u30B9\u30C8\u6240\u8981\u6642\u9593
|
||||
Test\ Result=\u30C6\u30B9\u30C8\u7D50\u679C
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Build=B\u016Bv\u0113jums
|
||||
Test\ Description=Testa Apraksts
|
||||
Test\ Duration=Testa Ilgums
|
||||
Test\ Result=Testa Rezult\u0101ts
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Test\ Description=Descri\u00e7\u00e3o do teste
|
||||
Build=Build
|
||||
Test\ Duration=Dura\u00e7\u00e3o do teste
|
||||
Test\ Result=Resultado do teste
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Build=\u0421\u0431\u043E\u0440\u043A\u0430
|
||||
Test\ Description=\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0442\u0435\u0441\u0442\u0430
|
||||
Test\ Duration=\u0414\u043B\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0442\u0435\u0441\u0442\u0430
|
||||
Test\ Result=\u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0442\u0435\u0441\u0442\u0430
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
Build=Bygge
|
||||
Test\ Description=Testbeskrivning
|
||||
Test\ Duration=Tids\u00E5tg\u00E5ng
|
||||
Test\ Result=Testresultat
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=\u5efa\u7f6e
|
||||
Test\ Duration=\u6e2c\u8a66\u4f7f\u7528\u6642\u9593
|
||||
Test\ Description=\u6e2c\u8a66\u8aaa\u660e
|
||||
Test\ Result=\u6e2c\u8a66\u7d50\u679c
|
|
@ -1,61 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2010, Sun Microsystems, Inc., Tom Huybrechts
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- this is loaded on demand in the failed test results summary -->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:local="local">
|
||||
<d:taglib uri="local">
|
||||
<d:tag name="item">
|
||||
<j:if test="${value!=null and !empty value}">
|
||||
<j:set var="id" value="${attrs.id}-${attrs.name}"/>
|
||||
<j:set var="display" value="${attrs.opened ? '' : 'none'}"/>
|
||||
<j:set var="idisplay" value="${attrs.opened ? 'none' : ''}"/>
|
||||
<j:set var="open" value="javascript:showFailureSummary('${id}')"/>
|
||||
<j:set var="close" value="javascript:hideFailureSummary('${id}')"/>
|
||||
<h4>
|
||||
<a id="${id}-showlink" href="${open}" title="Show ${title}" style="display: ${idisplay}">
|
||||
<l:icon class="icon-document-add icon-sm"/><st:nbsp/>${title}
|
||||
</a>
|
||||
<a id="${id}-hidelink" href="${close}" title="Hide ${title}" style="display: ${display}">
|
||||
<l:icon class="icon-document-delete icon-sm"/><st:nbsp/>${title}
|
||||
</a>
|
||||
</h4>
|
||||
<pre id="${id}" style="display: ${display}">
|
||||
<st:out value="${value}"/>
|
||||
</pre>
|
||||
</j:if>
|
||||
</d:tag>
|
||||
</d:taglib>
|
||||
<st:contentType value="text/plain;charset=UTF-8"/>
|
||||
|
||||
<j:new var="h" className="hudson.Functions" />
|
||||
${h.initPageVariables(context)}
|
||||
|
||||
<j:set var="id" value="${h.generateId()}"/>
|
||||
|
||||
<local:item id="${id}" name="error" title="${%Error Details}" value="${it.errorDetails}" opened="true"/>
|
||||
<local:item id="${id}" name="stacktrace" title="${%Stack Trace}" value="${it.errorStackTrace}"/>
|
||||
<local:item id="${id}" name="stdout" title="${%Standard Output}" value="${it.stdout}"/>
|
||||
<local:item id="${id}" name="stderr" title="${%Standard Error}" value="${it.stderr}"/>
|
||||
</j:jelly>
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=Fejl detaljer
|
||||
Stack\ Trace=Stack Trace
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=Fehlerdetails
|
||||
Stack\ Trace=Stacktrace
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=Detalles del error
|
||||
Stack\ Trace=Traza de la pila
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Seiji Sogabe
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=\u30A8\u30E9\u30FC\u8A73\u7D30
|
||||
Stack\ Trace=\u30B9\u30BF\u30C3\u30AF\u30C8\u30EC\u30FC\u30B9
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=Detalhes de erro
|
||||
Stack\ Trace=Stack trace
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Error\ Details=\u932f\u8aa4\u8a73\u7d30\u8cc7\u6599
|
||||
Stack\ Trace=\u5806\u758a\u8ffd\u8e64
|
|
@ -1,56 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:cactusman
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<j:if test="${it.totalCount!=0}">
|
||||
<h2>${%All Tests}</h2>
|
||||
<table class="pane sortable bigtable" id="testresult">
|
||||
<tr>
|
||||
<td class="pane-header">${%Test name}</td>
|
||||
<td class="pane-header" style="width:6em">${%Duration}</td>
|
||||
<td class="pane-header" style="width:6em">${%Status}</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
<j:forEach var="p" items="${it.children}" varStatus="status">
|
||||
<tr>
|
||||
<td class="pane">
|
||||
<a href="${p.safeName}" class="model-link inside"><span style="${p.previousResult==null?'font-weight:bold':''}"><st:out value="${p.displayName}" /></span></a>
|
||||
<j:forEach var="badge" items="${p.testActions}">
|
||||
<st:include it="${badge}" page="badge.jelly" optional="true"/>
|
||||
</j:forEach>
|
||||
</td>
|
||||
<td class="pane" style="width:6em" data="${p.duration}">${p.durationString}</td>
|
||||
<td class="pane" style="width:6em">
|
||||
<j:set var="pst" value="${p.status}" />
|
||||
<span class="${pst.cssClass}">
|
||||
${pst.message}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</j:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</j:if>
|
||||
</j:jelly>
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Duration=Varighed
|
||||
Status=Status
|
||||
Test\ name=Test navn
|
||||
All\ Tests=Alle test
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Alle Tests
|
||||
Test\ name=Testname
|
||||
Duration=Dauer
|
||||
Status=Status
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Todos los tests
|
||||
Test\ name=Nombre del test
|
||||
Duration=Duración
|
||||
Status=Estado
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Kaikki testit
|
||||
Duration=Kesto
|
||||
Status=Tila
|
||||
Test\ name=Testin nimi
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Tous les tests
|
||||
Test\ name=Nom du test
|
||||
Duration=Durée
|
||||
Status=Statut
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:cactusman
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=\u3059\u3079\u3066\u306e\u30c6\u30b9\u30c8
|
||||
Test\ name=\u30c6\u30b9\u30c8\u540d
|
||||
Duration=\u30c6\u30b9\u30c8\u6240\u8981\u6642\u9593
|
||||
Status=\u72b6\u614b
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
All\ Tests=Visi testi
|
||||
Duration=Ilgums
|
||||
Status=St\u0101voklis
|
||||
Test\ name=Testa nosaukums
|
|
@ -1,5 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
All\ Tests=Alle Tester
|
||||
Duration=Varighet
|
||||
Test\ name=Testnavn
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:sorokh
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Alle testen
|
||||
Test\ name=Naam van de test
|
||||
Duration=Duur
|
||||
Status=Status
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Todos os testes
|
||||
Test\ name=Nome do teste
|
||||
Duration=Dura\u00e7\u00e3o
|
||||
Status=Estado
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Mike Salnikov
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=\u0412\u0441\u0435 \u0442\u0435\u0441\u0442\u044b
|
||||
Test\ name=\u0418\u043c\u044f \u0442\u0435\u0441\u0442\u0430
|
||||
Duration=\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c
|
||||
Status=\u0421\u0442\u0430\u0442\u0443\u0441
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=Alla tester
|
||||
Duration=Tid
|
||||
Status=Status
|
||||
Test\ name=Testnamn
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Oguz Dag
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=T\u00fcm Testler
|
||||
Test\ name=Test Ad\u0131
|
||||
Duration=S\u00fcre
|
||||
Status=Durum
|
|
@ -1,6 +0,0 @@
|
|||
# This file is under the MIT License by authors
|
||||
|
||||
All\ Tests=\u6D4B\u8BD5\u7528\u4F8B
|
||||
Duration=\u8FD0\u884C\u65F6\u95F4
|
||||
Status=\u7ED3\u679C
|
||||
Test\ name=\u6D4B\u8BD5\u540D\u79F0
|
|
@ -1,27 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2013, Sun Microsystems, Inc., Chunghwa Telecom Co., Ltd.,
|
||||
# and Pei-Tang Huang
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
All\ Tests=\u6240\u6709\u6e2c\u8a66
|
||||
Test\ name=\u6e2c\u8a66\u540d\u7a31
|
||||
Duration=\u82b1\u8cbb\u6642\u9593
|
||||
Status=\u72c0\u614b
|
|
@ -1,58 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2009, Sun Microsystems, Inc., Tom Huybrechts
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
|
||||
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
|
||||
<table class="pane sortable bigtable" id="testresult">
|
||||
<tr>
|
||||
<td class="pane-header">${%Build}</td>
|
||||
<td class="pane-header">${%Description}</td>
|
||||
<td class="pane-header" style="width:5em">${%Duration}</td>
|
||||
<td class="pane-header" style="width:5em">${%Fail}</td>
|
||||
<td class="pane-header" style="width:5em">${%Skip}</td>
|
||||
<td class="pane-header" style="width:5em">${%Total}</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
<j:forEach var="b" items="${it.owner.parent.builds}" begin="${start}" end="${end}">
|
||||
<j:set var="p" value="${it.getResultInBuild(b)}"/>
|
||||
<j:if test="${p != null}">
|
||||
<tr>
|
||||
<td class="pane">
|
||||
<a href="${app.rootUrl}${b.url}testReport${p.url}" class="model-link">${b.fullDisplayName}</a>
|
||||
<j:forEach var="badge" items="${p.testActions}">
|
||||
<st:include it="${badge}" page="badge.jelly" optional="true"/>
|
||||
</j:forEach>
|
||||
</td>
|
||||
<td class="pane" style="text-align:right"><j:out value="${p.description}"/></td>
|
||||
<td class="pane" style="text-align:right" data="${p.duration}">${p.durationString}</td>
|
||||
<td class="pane" style="text-align:right">${p.failCount}</td>
|
||||
<td class="pane" style="text-align:right">${p.skipCount}</td>
|
||||
<td class="pane" style="text-align:right">${p.totalCount}</td>
|
||||
</tr>
|
||||
</j:if>
|
||||
</j:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</j:jelly>
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Duration=Varighed
|
||||
Build=Byg
|
||||
Skip=Spring over
|
||||
Total=I alt
|
||||
Fail=Fejler
|
||||
Description=Beskrivelse
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Build
|
||||
Description=Beschreibung
|
||||
Duration=Dauer
|
||||
Fail=Fehlgeschlagen
|
||||
Skip=Ausgelassen
|
||||
Total=Summe
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=Ejecución
|
||||
Description=Descripción
|
||||
Duration=Duración
|
||||
Fail=Fallo
|
||||
Skip=Omitidos
|
||||
Total=Total
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Seiji Sogabe
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=\u30D3\u30EB\u30C9
|
||||
Description=\u30C6\u30B9\u30C8\u306E\u8AAC\u660E
|
||||
Duration=\u30C6\u30B9\u30C8\u6240\u8981\u6642\u9593
|
||||
Fail=\u5931\u6557
|
||||
Skip=\u30B9\u30AD\u30C3\u30D7
|
||||
Total=\u5408\u8A08
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva, Fernando Boaglio
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Skip=pular
|
||||
Duration=Dura\u00e7\u00e3o
|
||||
Total=Total
|
||||
Build=Build
|
||||
Fail=Falha
|
||||
Description=Descri\u00e7\u00e3o
|
|
@ -1,27 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Description=\u63CF\u8FF0
|
||||
Duration=\u8017\u65F6
|
||||
Fail=\u5931\u8D25
|
||||
Skip=\u8DF3\u8FC7
|
||||
Total=\u5408\u8BA1
|
|
@ -1,28 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
Build=\u5efa\u7f6e
|
||||
Duration=\u82b1\u8cbb\u6642\u9593
|
||||
Description=\u8aaa\u660e
|
||||
Fail=\u5931\u6557
|
||||
Skip=\u7565\u904e
|
||||
Total=\u7e3d\u8a08
|
|
@ -1,79 +0,0 @@
|
|||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2009, Sun Microsystems, 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
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- Displays the chart that show how long builds are taking -->
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
|
||||
<l:layout title="${%title(it.testObject.displayName)}">
|
||||
<j:set var="start" value="${it.asInt(request.getParameter('start'),0)}"/>
|
||||
<j:set var="end" value="${it.asInt(request.getParameter('end'),start+24)}"/>
|
||||
<j:set var="rangeParameters" value="start=${start}&end=${end+1}"/>
|
||||
<script type="text/javascript">
|
||||
function setCount() {
|
||||
document.getElementById("graph").src = "countGraph/png?${rangeParameters}";
|
||||
document.getElementById("graph").lazyMap = "countGraph/map?${rangeParameters}";
|
||||
document.getElementById("graph").alt = "[Count graph]";
|
||||
document.getElementById("duration-link").style.display = "";
|
||||
document.getElementById("count-link").style.display = "none";
|
||||
}
|
||||
function setDuration() {
|
||||
document.getElementById("graph").src = "durationGraph/png?${rangeParameters}"
|
||||
document.getElementById("graph").lazyMap = "durationGraph/map?${rangeParameters}"
|
||||
document.getElementById("graph").alt = "[Duration graph]";
|
||||
document.getElementById("duration-link").style.display = "none";
|
||||
document.getElementById("count-link").style.display = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<st:include from="${it.testObject}" it="${it.testObject}" page="sidepanel.jelly" />
|
||||
<l:main-panel>
|
||||
<H2>${%title(it.testObject.displayName)}</H2>
|
||||
<j:choose>
|
||||
<j:when test="${it.historyAvailable()}">
|
||||
<div align="center">
|
||||
<img id="graph" src="durationGraph/png?${rangeParameters}" width="600" height="300" lazymap="durationGraph/map?${rangeParameters}" alt="[Duration graph]"/>
|
||||
</div>
|
||||
<div align="center">
|
||||
show
|
||||
<a id="count-link" href="#" onclick='javascript:setCount()'>count</a>
|
||||
<a id="duration-link" href="#" onclick="javascript:setDuration()" style="display:none;">duration</a>
|
||||
</div>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
${%More than 1 builds are needed for the chart.}
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
<st:include from="${it.testObject}" it="${it.testObject}" page="list.jelly" optional="true"/>
|
||||
<div>
|
||||
<j:if test="${start > 0}">
|
||||
<a href="${app.rootUrl}${it.testObject.owner.url}testReport${it.testObject.url}/history${(start-25)>0?'?start='+(start-25):''}">${%Newer}</a>
|
||||
</j:if>
|
||||
|
||||
<j:if test="${it.testObject.owner.project.builds.size() > end}">
|
||||
<a href="${app.rootUrl}${it.testObject.owner.url}testReport${it.testObject.url}/history?start=${end+1}">${%Older}</a>
|
||||
</j:if>
|
||||
</div>
|
||||
</l:main-panel>
|
||||
</l:layout>
|
||||
</j:jelly>
|
|
@ -1,23 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Seiji Sogabe
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
title=History for {0}
|
|
@ -1,24 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen.
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
More\ than\ 1\ builds\ are\ needed\ for\ the\ chart.=Mere end 1 byg er n\u00f8dvendigt for grafen.
|
||||
title=Historik for {0}
|
|
@ -1,26 +0,0 @@
|
|||
# The MIT License
|
||||
#
|
||||
# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest
|
||||
#
|
||||
# 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
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
title=Verlauf von {0}
|
||||
More\ than\ 1\ builds\ are\ needed\ for\ the\ chart.=Für ein Diagramm werden mindestens 2 Builds benötigt.
|
||||
Older=Älter
|
||||
Newer=Neuer
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue