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