[FIXED JENKINS-23263] JUnit reporter moved to a plugin.

This commit is contained in:
Jesse Glick 2014-08-11 13:45:23 -04:00
parent ec22212b78
commit 16197ea502
471 changed files with 41 additions and 45006 deletions

View File

@ -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=-->

View File

@ -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")
);
/**

View File

@ -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;
}
}
/**

View File

@ -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

View File

@ -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>

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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)))
));
}
}
}

View File

@ -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);
}
}

View File

@ -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 &lt;testsuite>
* elements wrapped into the top-level &lt;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");
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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());
}

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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");
}

View File

@ -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();
}

View File

@ -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>());
}

View File

@ -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 "";
}
}

View File

@ -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;
}

View File

@ -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("&", "&amp;").replace("<", "&lt;").replaceAll(
"\\b(https?://[^\\s)>]+)", "<a href=\"$1\">$1</a>");
for (TestAction action: getTestActions()) {
text = action.annotate(text);
}
return text;
}
}

View File

@ -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;
}

View File

@ -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";
}

View File

@ -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>

View File

@ -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 {

View File

@ -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 &amp;&amp; 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>

View File

@ -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=' '

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}.

View File

@ -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}

View File

@ -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}.

View File

@ -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.

View File

@ -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

View File

@ -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}.

View File

@ -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}.

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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)

View File

@ -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}.

View File

@ -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)

View File

@ -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}.

View File

@ -1,3 +0,0 @@
# This file is under the MIT License by authors
took=\u8FD0\u884C\u65F6\u95F4\uFF1A{0}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +0,0 @@
# This file is under the MIT License by authors
All\ Tests=Alle Tester
Duration=Varighet
Test\ name=Testnavn

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}&amp;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>

View File

@ -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}

View File

@ -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}

View File

@ -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