Package hudson.tasks.test

Source Code of hudson.tasks.test.TestObject

/*
* 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 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.
     * @return
     */
    @Override
    public hudson.tasks.junit.TestResult getTestResult() {
        TestObject parent = getParent();

        return (parent == null ? null : getParent().getTestResult());
    }

    /**
     * Returns the top level test result data.
     *
     * @return
     */   
    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 ancesotors 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 = Hudson.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.
     * @return
     */
    @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
     * @return
     */
    @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>
     * withint 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 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 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;
            }
        }
        UNIQUIFIED_NAMES.put(this, uniquified);
        return uniquified;
    }
    private static final Map<TestObject, String> UNIQUIFIED_NAMES = new MapMaker().weakKeys().makeMap();

    /**
     * Replaces URL-unsafe characters.
     */
    public static String safe(String s) {
        // 3 replace calls is still 2-3x faster than a regex replaceAll
        return s.replace('/', '_').replace('\\', '_').replace(':', '_');
    }

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

Related Classes of hudson.tasks.test.TestObject

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.