Hi Vincent and Dave,

Sorry, I had take mistake.

In article <[EMAIL PROTECTED]>,
Tue, 3 Feb 2004 16:30:47 +1200,
[EMAIL PROTECTED] wrote: 
dsearle> 2 Modify Servlet Test Runner (or create a new runner) that can run in a
dsearle> asynchronous mode.
dsearle> This would involve spawning a thread to run the actual test and storing the
dsearle> TestResult somewhere (e.g. ServletContext) with an ID.
dsearle> The browser could then reload the page (automatically if required) with an ID
dsearle> for the TestResult. My only concern with this approach is any threading 
issues?

I wrote such kind of Servlet Test Runner before, and find it.
I don't use this Servlet Test Runner because I decided to not use browser
interface. So, the classes are not maintaind for a long time.
However, I think this is good enough for the stat point.

Regards,
----
Kazuhito SUGURI
mailto:[EMAIL PROTECTED]
/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Cactus" and "Apache Software
 *    Foundation" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.cactus.server.runner;

import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Hashtable;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import junit.framework.Test;
import junit.framework.TestResult;

import org.apache.cactus.configuration.BaseConfiguration;

/**
 * Helper servlet to start a JUnit Test Runner in a webapp.
 * 
 * <p>
 *   This class currently does a couple of reflection tricks to avoid a direct 
 *   dependancy on the TraX API (<code>javax.xml.transform.*</code>),
 *   encapsulated in the [EMAIL PROTECTED] XMLTransformer} class.
 * </p>
 * 
 * @author <a href="mailto:[EMAIL PROTECTED]">Vincent Massol</a>
 * @author <a href="mailto:[EMAIL PROTECTED]">Christopher Lenz</a>
 *
 * @author Kazuhito SUGURI
 *
 * @version $Id$
 */
public class CustomServletTestRunner
    extends HttpServlet
{
    /**
     * ServletContext attribute name for ThreadTestRunner Container.
     */
    private static final String TEST_RUNNER_CONTAINER_ATTR
        = "org.apache.cactus.server.runner.ThreadTestRunnerContainer";

    /**
     * HTTP parameter containing id to find existing TestTestRunner.
     */
    private static final String HTTP_ORDERID_PARAM = "orderid";

    /**
     * HTTP parameter containing name of test suite to execute
     */
    private static final String HTTP_SUITE_PARAM = "suite";

    /**
     * HTTP parameter that determines whether the XML test results should be 
     * transformed using the XSLT stylesheet specified as initialization 
     * parameter.
     */
    private static final String HTTP_TRANSFORM_PARAM = "transform";

    /**
     * HTTP parameter containing name of the XSL stylesheet to put in the
     * returned XML test result. It will only work if the browser supports
     * this feature (IE does, I don't know about others).
     */
    private static final String HTTP_XSL_PARAM = "xsl";

    /**
     * Name of the servlet initialization parameter that contains the path to
     * the XSLT stylesheet for transforming the XML report into HTML.
     */
    private static final String XSL_STYLESHEET_PARAM = "xsl-stylesheet";


    /**
     * Name of the servlet initialization parameter that specifies
     * web-refresh interval time in sec.
     */
    private static final String REFRESH_INTERVAL_PARAM = "refresh-interval";

    /**
     * The default web-refresh interval time in sec.
     */
    private static final int DEFAULT_REFRESH_INTERVAL = 5;

    /**
     * The XML transformer. Avoid direct dependancy by using reflection.
     */
    private Object transformer = null;

    /**
     * Indicates whether the servlet has sufficient permissions to set a
     * system property, to be able to set the cactus.contentURL property. This
     * is set to false if the first attempt to set the property throws a
     * SecurityException.
     */
    private boolean canSetSystemProperty = true;


    private int refreshInterval;

    /**
     * Called by the container when the servlet is initialized.
     * 
     * @throws ServletException If an initialization parameter contains an
     *         illegal value
     */
    public void init()
        throws ServletException
    {
        initXSLTprocessor();
        initTestRunnerContainer();
        refreshInterval = getRefreshInterval();
    }

    private void initXSLTprocessor()
        throws ServletException
    {
        // Check whether XSLT transformations should be done server-side and
        // build the templates if an XSLT processor is available
        String xslStylesheetParam = getInitParameter(XSL_STYLESHEET_PARAM);
        if (xslStylesheetParam != null)
        {
            InputStream xslStylesheet =
                getServletContext().getResourceAsStream(xslStylesheetParam);
            if (xslStylesheet != null)
            {
                try
                {
                    Class transformerClass = Class.forName(
                        "org.apache.cactus.server.runner.XMLTransformer");
                    Constructor transformerCtor = 
                        transformerClass.getConstructor(
                        new Class[] {InputStream.class});
                    transformer = transformerCtor.newInstance(
                        new Object[] {xslStylesheet});
                }
                catch (Throwable t)
                {
                    log("Could not instantiate XMLTransformer - will not "
                        + "perform server-side XSLT transformations", t);
                }
            }
            else
            {
                throw new UnavailableException(
                    "The initialization parameter 'xsl-stylesheet' does not "
                    + "refer to an existing resource");
            }
        }
    }

    /**
     * Prepare ThreadTestRunner Container.
     */
    private synchronized void initTestRunnerContainer(){
        Hashtable container = getTestRunnerContainer();
        if(container==null){
            setTestRunnerContainer(new Hashtable());
        }
    }

    private synchronized void setTestRunnerContainer(Hashtable container){
        getServletContext().setAttribute(TEST_RUNNER_CONTAINER_ATTR,
                                         container);
    }

    /**
     * Get current ThreadTestRunner Container.
     */
    private Hashtable getTestRunnerContainer(){
        ServletContext context = getServletContext();
        return (Hashtable)context.getAttribute(TEST_RUNNER_CONTAINER_ATTR);
    }

    /**
     * get refresh interval value.
     */
    private int getRefreshInterval(){
        try{
            String interval = getInitParameter(REFRESH_INTERVAL_PARAM);
            return Integer.parseInt(interval);
        }catch(Exception e){
            return DEFAULT_REFRESH_INTERVAL;
        }
    }

    /**
     * Starts the test suite passed as a HTTP parameter
     *
     * @param theRequest the incoming HTTP client request
     * @param theResponse the outgoing HTTP client request to send back.
     *
     * @exception ServletException if an error occurs when servicing the
     *            request
     * @exception IOException if an error occurs when servicing the request
     */
    public void doGet(HttpServletRequest theRequest, 
                      HttpServletResponse theResponse)
        throws ServletException, IOException
    {
        ThreadTestRunner runner;

        String orderId = theRequest.getParameter(HTTP_ORDERID_PARAM);
        if(orderId==null){
            try{
                runner = getNewTestRunner(theRequest, theResponse);
                runner.start();
            }catch(Exception e){
                throw new ServletException("cannot start ThreadTestRunner",
                                           e);
            }
            addTestRunner(runner.getId(), runner);
            responseRedirect(theRequest, theResponse, runner);
            return;
        }

        runner = getTestRunner(orderId);
        if(runner==null){
            throw new ServletException("no ThreadTestRunner exists [id="
                                       + orderId
                                       + "]");
        }

        if(runner.isAlive()){
            responseRefresh(theRequest, theResponse, runner);
        }else{
            responseResult(theRequest, theResponse, runner);
        }
    }


    private void responseRefresh(HttpServletRequest theRequest, 
                                 HttpServletResponse theResponse,
                                 ThreadTestRunner runner)
        throws ServletException, IOException
    {
        theResponse.setHeader("Pragma", "no-cache");
        theResponse.setHeader("Cache-Control", "no-cache");
        theResponse.setIntHeader("Refresh", refreshInterval);
        theResponse.setContentType("text/plain");

        PrintWriter out = theResponse.getWriter();
        out.print("now testing (id=");
        out.print(runner.getId());
        out.println(")");
    }


    private void responseRedirect(HttpServletRequest theRequest, 
                                  HttpServletResponse theResponse,
                                  ThreadTestRunner runner)
        throws ServletException, IOException
    {
        theResponse.setStatus(theResponse.SC_MOVED_TEMPORARILY);
        theResponse.setHeader("Location",
                              theRequest.getRequestURI()
                              + "?"
                              + HTTP_ORDERID_PARAM
                              + "="
                              + runner.getId());
    }


    private void responseResult(HttpServletRequest theRequest,
                                HttpServletResponse theResponse,
                                ThreadTestRunner runner)
        throws ServletException, IOException
    {
        String xml = runner.getResult();
        removeTestRunner(runner);

        if(runner.transformRequired() && (transformer!=null)){
            try {
                Method getContentTypeMethod
                    = transformer.getClass().getMethod("getContentType",
                                                       new Class[0]);
                String contentType
                    = (String)getContentTypeMethod.invoke(transformer,
                                                          new Object[0]);
                theResponse.setContentType(contentType);
                                           
                PrintWriter out = theResponse.getWriter();
                Method transformMethod
                    = transformer.getClass().getMethod("transform",
                                                       new Class[]{Reader.class,
                                                                   Writer.class});     
          
                                                       
                transformMethod.invoke(transformer,
                                       new Object[]{new StringReader(xml),
                                                    out});
            }catch (Exception e){
                throw new ServletException("Problem applying the XSLT transformation",
                                           e);
            }
        }else{
            // Transform client side (or not at all)
            theResponse.setContentType("text/xml");
            PrintWriter pw = theResponse.getWriter();
            pw.println(xml);
        }
    }


    private ThreadTestRunner getNewTestRunner(HttpServletRequest theRequest, 
                                              HttpServletResponse theResponse)
        throws Exception
    {
        String orderId = getNewOrderId(theRequest);
        ThreadTestRunner runner = new ThreadTestRunner(orderId);

        // Verify if a suite parameter exists
        String suiteClassName = theRequest.getParameter(HTTP_SUITE_PARAM);
        if(suiteClassName==null){
            throw new ServletException("Missing HTTP parameter ["
                                       + HTTP_SUITE_PARAM
                                       + "] in request");
        }
        runner.setTestSuite(suiteClassName);

        // Get the XSL stylesheet parameter if any
        String xslParam = theRequest.getParameter(HTTP_XSL_PARAM);
        runner.setXslFilename(xslParam);

        // Get the transform parameter if any
        String transformParam = theRequest.getParameter(HTTP_TRANSFORM_PARAM);
        runner.setTransform((transformParam!=null));

        String contextURL = getContextURL(theRequest);
        runner.setSystemProperty(BaseConfiguration.CACTUS_CONTEXT_URL_PROPERTY,
                                 contextURL);

        return runner;
    }

    private ThreadTestRunner getTestRunner(String orderId){
        Hashtable container = getTestRunnerContainer();
        return (ThreadTestRunner)container.get(orderId);
    }

    /**
     * add new ThreadTestRunner instance associated with orderId
     * to the Container.
     */
    private synchronized void addTestRunner(String orderId,
                                            ThreadTestRunner runner)
    {
        Hashtable container = getTestRunnerContainer();
        container.put(runner.getId(), runner);
        setTestRunnerContainer(container);
    }

    private synchronized void removeTestRunner(ThreadTestRunner runner){
        Hashtable container = getTestRunnerContainer();
        container.remove(runner.getId());
        setTestRunnerContainer(container);
    }

    private String getNewOrderId(HttpServletRequest theRequest){
        // TODO: more stronger..
        StringBuffer id = new StringBuffer();
        id.append(theRequest.getServerName());
        id.append("-");
        id.append(Long.toHexString(System.currentTimeMillis()));
        return id.toString();
    }

    private String getContextURL(HttpServletRequest theRequest){
        StringBuffer context = new StringBuffer();
        context.append("http://";);
        context.append(theRequest.getServerName());
        context.append(":");
        context.append(theRequest.getServerPort());
        context.append(theRequest.getContextPath());
        return context.toString();
    }
}
/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Cactus" and "Apache Software
 *    Foundation" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.cactus.server.runner;

import junit.framework.Test;
import junit.framework.TestResult;

public class ThreadTestRunner
    extends Thread
{
    private boolean canSetSystemProperty = true;
    private XMLFormatter formatter;
    private String id;
    private TestResult result;
    private Test suite;
    private WebappTestRunner testRunner;
    private boolean transform = false;

    public ThreadTestRunner(String orderId){
        id = orderId;
        formatter = new XMLFormatter();
        result = new TestResult();
        testRunner = new WebappTestRunner();
    }

    public void setTestSuite(String theSuiteClassName)
        throws Exception
    {
        suite = testRunner.getTest(theSuiteClassName);

        if(suite==null){
            throw new Exception("Failed to load test suite ["
                                + theSuiteClassName
                                + "], Reason is ["
                                + testRunner.getErrorMessage()
                                + "]");
        }

        formatter.setSuiteClassName(theSuiteClassName);
    }

    public void setXslFilename(String theXslFileName){
        formatter.setXslFileName(theXslFileName);
    }

    public void setTransform(boolean flag){
        transform = flag;
    }

    /**
     * Set System property for test-runner.
     */
    public void setSystemProperty(String name, String value)
        throws SecurityException
    {
        if(! this.canSetSystemProperty){
            return;
        }
        if((name==null) || (value==null)){
            return;
        }

        try {
            System.setProperty(name, value);
        }catch (SecurityException se){
            this.canSetSystemProperty = false;
            throw se;
        }
    }

    
    /**
     * Run the suite tests.
     */
    public void run(){
        result.addListener(formatter);
        long startTime = System.currentTimeMillis();
        suite.run(this.result);
        long endTime = System.currentTimeMillis();
        formatter.setTotalDuration(endTime - startTime);
    }

    /**
     * return the result.
     */
    public String getResult(){
        if(! this.isAlive()){
            return formatter.toXML(this.result);
        }else{
            return "now running";
        }
    }

    public boolean transformRequired(){
        return transform;
    }

    public String getId(){
        return this.id;
    }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to