/*******************************************************************************
*
* Copyright (c) 2004-2009 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Kohsuke Kawaguchi, Daniel Dyer, Red Hat, Inc., Yahoo!, Inc.
*
*
*******************************************************************************/
package hudson.tasks.test;
import hudson.model.AbstractBuild;
import hudson.tasks.junit.CaseResult;
import hudson.tasks.junit.TestResult;
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.
*/
//TODO: review and check whether we can do it private
public final List<Child> children = new ArrayList<Child>();
public List<Child> getChildren() {
return children;
}
public AggregatedTestResultAction(AbstractBuild owner) {
super(owner);
}
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<CaseResult> getFailedTests() {
List<CaseResult> failedTests = new ArrayList<CaseResult>(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 {
//TODO: review and check whether we can do it private
@Exported
public final AbstractBuild<?, ?> child;
//TODO: review and check whether we can do it private
@Exported
public final Object result;
public AbstractBuild getChild() {
return child;
}
public Object getResult() {
return result;
}
public ChildReport(AbstractBuild<?, ?> child, AbstractTestResultAction result) {
this.child = child;
this.result = result.getResult();
}
}
/**
* 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();
}
}