Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FIXED JENKINS-15818] Display exceedingly slow for large test results.
  • Loading branch information
jglick committed Nov 13, 2012
1 parent f8b6af8 commit 734e7e0
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 25 deletions.
3 changes: 3 additions & 0 deletions changelog.html
Expand Up @@ -61,6 +61,9 @@
<li class=bug>
Build records were broken if timezone was changed while running.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-15816">issue 15816</a>)
<li class='major bug'>
Displaying massive test suite results could bring down Jenkins.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-15818">issue 15818</a>)
</ul>
</div><!--=TRUNK-END=-->

Expand Down
8 changes: 6 additions & 2 deletions core/src/main/java/hudson/tasks/junit/CaseResult.java
Expand Up @@ -54,6 +54,7 @@ public final class CaseResult extends TestResult implements Comparable<CaseResul
* This field retains the method name.
*/
private final String testName;
private transient String safeName;
private final boolean skipped;
private final String errorStackTrace;
private final String errorDetails;
Expand Down Expand Up @@ -232,15 +233,18 @@ public float getDuration() {
/**
* Gets the version of {@link #getName()} that's URL-safe.
*/
public @Override String getSafeName() {
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 uniquifyName(siblings, buf.toString());
return safeName = uniquifyName(siblings, buf.toString());
}

/**
Expand Down
8 changes: 6 additions & 2 deletions core/src/main/java/hudson/tasks/junit/ClassResult.java
Expand Up @@ -42,6 +42,7 @@
*/
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>();

Expand Down Expand Up @@ -112,8 +113,11 @@ public String getName() {
else return className.substring(idx+1);
}

public @Override String getSafeName() {
return uniquifyName(parent.getChildren(), safe(getName()));
public @Override synchronized String getSafeName() {
if (safeName != null) {
return safeName;
}
return safeName = uniquifyName(parent.getChildren(), safe(getName()));
}

public CaseResult getCaseResult(String name) {
Expand Down
8 changes: 6 additions & 2 deletions core/src/main/java/hudson/tasks/junit/PackageResult.java
Expand Up @@ -40,6 +40,7 @@
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.
*/
Expand Down Expand Up @@ -68,9 +69,12 @@ public String getName() {
}

@Override
public String getSafeName() {
public synchronized String getSafeName() {
if (safeName != null) {
return safeName;
}
Collection<PackageResult> siblings = (parent == null ? Collections.EMPTY_LIST : parent.getChildren());
return uniquifyName(
return safeName = uniquifyName(
siblings,
safe(getName()));
}
Expand Down
20 changes: 15 additions & 5 deletions core/src/main/java/hudson/tasks/junit/SuiteResult.java
Expand Up @@ -42,8 +42,10 @@
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
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;
Expand Down Expand Up @@ -80,6 +82,7 @@ public final class SuiteResult implements Serializable {
* 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) {
Expand All @@ -89,6 +92,16 @@ public final class SuiteResult implements Serializable {
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
Expand Down Expand Up @@ -217,6 +230,7 @@ private SuiteResult(File xmlReport, Element suite, boolean keepLongStdio) throws

/*package*/ void addCase(CaseResult cr) {
cases.add(cr);
casesByName().put(cr.getName(), cr);
duration += cr.getDuration();
}

Expand Down Expand Up @@ -294,11 +308,7 @@ public SuiteResult getPreviousResult() {
* Note that test name needs not be unique.
*/
public CaseResult getCase(String name) {
for (CaseResult c : cases) {
if(c.getName().equals(name))
return c;
}
return null;
return casesByName().get(name);
}

public Set<String> getClassNames() {
Expand Down
30 changes: 16 additions & 14 deletions core/src/main/java/hudson/tasks/test/TestObject.java
Expand Up @@ -32,17 +32,13 @@
import hudson.tasks.junit.TestResultAction;
import jenkins.model.Jenkins;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
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.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.logging.Logger;

Expand Down Expand Up @@ -335,19 +331,25 @@ public String getSearchUrl() {
/**
* #2988: uniquifies a {@link #getSafeName} amongst children of the parent.
*/
protected final synchronized String uniquifyName(
Collection<? extends TestObject> siblings, String base) {
String uniquified = base;
int sequence = 1;
for (TestObject sibling : siblings) {
if (sibling != this && uniquified.equals(UNIQUIFIED_NAMES.get(sibling))) {
uniquified = base + '_' + ++sequence;
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;
}
UNIQUIFIED_NAMES.put(this, uniquified);
return uniquified;
}
private static final Map<TestObject, String> UNIQUIFIED_NAMES = new MapMaker().weakKeys().makeMap();
private static final Map<String,Map<TestObject,Void>> UNIQUIFIED_NAMES = new MapMaker().makeMap();

/**
* Replaces URL-unsafe characters.
Expand Down

0 comments on commit 734e7e0

Please sign in to comment.