Package org.apache.cactus.internal.client

Source Code of org.apache.cactus.internal.client.ClientTestCaseCaller

/*
* ========================================================================
*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package org.apache.cactus.internal.client;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import junit.framework.Assert;
import junit.framework.Test;

import org.apache.cactus.Request;
import org.apache.cactus.internal.util.JUnitVersionHelper;
import org.apache.cactus.internal.util.TestCaseImplementChecker;
import org.apache.cactus.spi.client.ResponseObjectFactory;
import org.apache.cactus.spi.client.connector.ProtocolHandler;
import org.apache.cactus.spi.client.connector.ProtocolState;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Provides the ability to run common code before and after each test on the
* client side. All the methods provided are independent of any communication
* protocol between client side and server side (HTTP, JMS, etc). Any protocol
* dependent methods must be provided and implemented in the
* {@link ProtocolHandler} implementation class.
* @version $Id: ClientTestCaseCaller.java,v 1.7 2004/04/10 15:52:17 vmassol Exp $
*/
public class ClientTestCaseCaller extends Assert
{
    /**
     * The prefix of a test method.
     */
    protected static final String TEST_METHOD_PREFIX = "test";

    /**
     * The prefix of a begin test method.
     */
    protected static final String BEGIN_METHOD_PREFIX = "begin";

    /**
     * The prefix of an end test method.
     */
    protected static final String END_METHOD_PREFIX = "end";

    /**
     * The name of the method that is called before each test on the client
     * side (if it exists).
     */
    protected static final String CLIENT_GLOBAL_BEGIN_METHOD = "begin";

    /**
     * The name of the method that is called after each test on the client
     * side (if it exists).
     */
    protected static final String CLIENT_GLOBAL_END_METHOD = "end";

    /**
     * The logger (only used on the client side).
     */
    private Log logger;

    /**
     * Pure JUnit Test Case that we are wrapping (if any)
     */
    private Test wrappedTest;

    /**
     * The test we are delegating for.
     */
    private Test delegatedTest;  

    /**
     * The protocol handler to use to execute the tests on the server side.
     */
    private ProtocolHandler protocolHandler;

    // Constructors ---------------------------------------------------------
   
    /**
     * @param theDelegatedTest the test we are delegating for
     * @param theWrappedTest the test being wrapped by this delegate (or null
     *        if none)
     * @param theProtocolHandler the protocol handler to use to execute the
     *        tests on the server side
     */
    public ClientTestCaseCaller(Test theDelegatedTest,
        Test theWrappedTest, ProtocolHandler theProtocolHandler)
    {       
        if (theDelegatedTest == null)
        {
            throw new IllegalStateException(
                "The test object passed must not be null");
        }

        setDelegatedTest(theDelegatedTest);
        setWrappedTest(theWrappedTest);
        this.protocolHandler = theProtocolHandler;
    }

    // Public methods -------------------------------------------------------
   
    /**
     * Execute begin and end methods and calls the different
     * {@link ProtocolHandler} lifecycle methods to execute the test
     * on the server side.
     *
     * Note that this method is overriden from the JUnit
     * {@link junit.framework.TestCase} class in order to prevent JUnit from
     * calling the {@link junit.framework.TestCase#setUp()} and
     * {@link junit.framework.TestCase#tearDown()} methods on the client side.
     * instead we are calling the server redirector proxy and the setup and
     * teardown methods will be executed on the server side.
     *
     * @exception Throwable if any error happens during the execution of
     *            the test
     */
    public void runTest() throws Throwable
    {
        Request request = this.protocolHandler.createRequest();
       
        // Call the set up and begin methods to fill the request object
        callGlobalBeginMethod(request);
        callBeginMethod(request);

        // Run the server test
        ProtocolState state = this.protocolHandler.runTest(
            getDelegatedTest(), getWrappedTest(), request);
       
        // Call the end method
        Object response = callEndMethod(request,
            this.protocolHandler.createResponseObjectFactory(state));

        // call the tear down method
        callGlobalEndMethod(request,
            this.protocolHandler.createResponseObjectFactory(state),
            response);

        this.protocolHandler.afterTest(state);
    }

    /**
     * @return The logger used by the <code>TestCase</code> class and
     *         subclasses to perform logging.
     */
    public final Log getLogger()
    {
        return this.logger;
    }

    /**
     * Perform client side initializations before each test, such as
     * re-initializating the logger and printing some logging information.
     */
    public void runBareInit()
    {
        // We make sure we reinitialize The logger with the name of the
        // current extending class so that log statements will contain the
        // actual class name (that's why the logged instance is not static).
        this.logger = LogFactory.getLog(this.getClass());

        // Mark beginning of test on client side
        getLogger().debug("------------- Test: " + this.getCurrentTestName());
    }

    /**
     * Call the test case begin method.
     *
     * @param theRequest the request object to pass to the begin method.
     * @exception Throwable any error that occurred when calling the begin
     *            method for the current test case.
     */
    public void callBeginMethod(Request theRequest) throws Throwable
    {
        callGenericBeginMethod(theRequest, getBeginMethodName());
    }

    /**
     * Call the test case end method
     *
     * @param theRequest the request data that were used to open the
     *                   connection.
     * @param theResponseFactory the factory to use to return response objects.
     * @return the created Reponse object
     * @exception Throwable any error that occurred when calling the end method
     *         for the current test case.
     */
    public Object callEndMethod(Request theRequest,
        ResponseObjectFactory theResponseFactory) throws Throwable
    {
        return callGenericEndMethod(theRequest, theResponseFactory,
            getEndMethodName(), null);
    }

    /**
     * Call the global begin method. This is the method that is called before
     * each test if it exists. It is called on the client side only.
     *
     * @param theRequest the request object which will contain data that will
     *        be used to connect to the Cactus server side redirectors.
     * @exception Throwable any error that occurred when calling the method
     */
    public void callGlobalBeginMethod(Request theRequest) throws Throwable
    {
        callGenericBeginMethod(theRequest, CLIENT_GLOBAL_BEGIN_METHOD);
    }

    /**
     * Call the client tear down up method if it exists.
     *
     * @param theRequest the request data that were used to open the
     *                   connection.
     * @param theResponseFactory the factory to use to return response objects.
     * @param theResponse the Response object if it exists. Can be null in
     *        which case it is created from the response object factory
     * @exception Throwable any error that occurred when calling the method
     */
    private void callGlobalEndMethod(Request theRequest,
        ResponseObjectFactory theResponseFactory, Object theResponse)
        throws Throwable
    {
        callGenericEndMethod(theRequest, theResponseFactory,
            CLIENT_GLOBAL_END_METHOD, theResponse);
    }
   
    // Private methods ------------------------------------------------------
   
    /**
     * @param theWrappedTest the pure JUnit test that we need to wrap
     */
    private void setWrappedTest(Test theWrappedTest)
    {
        this.wrappedTest = theWrappedTest;
    }

    /**
     * @param theDelegatedTest the test we are delegating for
     */
    private void setDelegatedTest(Test theDelegatedTest)
    {
        this.delegatedTest = theDelegatedTest;
    }

    /**
     * @return the wrapped JUnit test
     */
    private Test getWrappedTest()
    {
        return this.wrappedTest;
    }

    /**
     * @return the test we are delegating for
     */
    private Test getDelegatedTest()
    {
        return this.delegatedTest;
    }

    /**
     * @return the test on which we will operate. If there is a wrapped
     *         test then the returned test is the wrapped test. Otherwise we
     *         return the delegated test.
     */
    private Test getTest()
    {
        Test activeTest;
        if (getWrappedTest() != null)
        {
            activeTest = getWrappedTest();
        }
        else
        {
            activeTest = getDelegatedTest();
        }
        return activeTest;
    }

    /**
     * @return the name of the test method to call without the
     *         TEST_METHOD_PREFIX prefix
     */
    private String getBaseMethodName()
    {
        // Sanity check
        if (!getCurrentTestName().startsWith(TEST_METHOD_PREFIX))
        {
            throw new RuntimeException("bad name ["
                + getCurrentTestName()
                + "]. It should start with ["
                + TEST_METHOD_PREFIX + "].");
        }

        return getCurrentTestName().substring(
            TEST_METHOD_PREFIX.length());
    }

    /**
     * @return the name of the test begin method to call that initialize the
     *         test by initializing the <code>WebRequest</code> object
     *         for the test case.
     */
    private String getBeginMethodName()
    {
        return BEGIN_METHOD_PREFIX + getBaseMethodName();
    }

    /**
     * @return the name of the test end method to call when the test has been
     *         run on the server. It can be used to verify returned headers,
     *         cookies, ...
     */
    private String getEndMethodName()
    {
        return END_METHOD_PREFIX + getBaseMethodName();
    }

    /**
     * Call a begin method which takes Cactus WebRequest as parameter
     *
     * @param theRequest the request object which will contain data that will
     *        be used to connect to the Cactus server side redirectors.
     * @param theMethodName the name of the begin method to call
     * @exception Throwable any error that occurred when calling the method
     */
    private void callGenericBeginMethod(Request theRequest,
        String theMethodName) throws Throwable
    {
        // First, verify if a begin method exist. If one is found, verify if
        // it has the correct signature. If not, send a warning.
        Method[] methods = getTest().getClass().getMethods();

        for (int i = 0; i < methods.length; i++)
        {
            if (methods[i].getName().equals(theMethodName))
            {
                TestCaseImplementChecker.checkAsBeginMethod(methods[i]);

                try
                {
                    methods[i].invoke(getTest(), new Object[] {theRequest});

                    break;
                }
                catch (InvocationTargetException e)
                {
                    e.fillInStackTrace();
                    throw e.getTargetException();
                }
                catch (IllegalAccessException e)
                {
                    e.fillInStackTrace();
                    throw e;
                }
            }
        }
    }

    /**
     * Call the global end method. This is the method that is called after
     * each test if it exists. It is called on the client side only.
     *
     * @param theRequest the request data that were used to open the
     *        connection.
     * @param theResponseFactory the factory to use to return response objects.
     * @param theMethodName the name of the end method to call
     * @param theResponse the Response object if it exists. Can be null in
     *        which case it is created from the response object factory
     * @return the created Reponse object
     * @exception Throwable any error that occurred when calling the end method
     *            for the current test case.
     */
    private Object callGenericEndMethod(Request theRequest,
        ResponseObjectFactory theResponseFactory, String theMethodName,
        Object theResponse) throws Throwable
    {
        Method methodToCall = null;
        Object paramObject = null;

        Method[] methods = getTest().getClass().getMethods();

        for (int i = 0; i < methods.length; i++)
        {
            if (methods[i].getName().equals(theMethodName))
            {
                TestCaseImplementChecker.checkAsEndMethod(methods[i]);

                paramObject = theResponse;

                if (paramObject == null)
                {
                    Class[] parameters = methods[i].getParameterTypes();
                    try
                    {
                        paramObject = theResponseFactory.getResponseObject(
                            parameters[0].getName(), theRequest);
                    }
                    catch (ClientException e)
                    {
                        throw new ClientException("The method ["
                            + methods[i].getName()
                            + "] has a bad parameter of type ["
                            + parameters[0].getName() + "]", e);
                    }
                }

                // Has a method to call already been found ?
                if (methodToCall != null)
                {
                    fail("There can only be one method ["
                       + methods[i].getName() + "] per test case. "
                       + "Test case [" + this.getCurrentTestName()
                       + "] has two at least !");
                }

                methodToCall = methods[i];
            }
        }

        if (methodToCall != null)
        {
            try
            {
                methodToCall.invoke(getTest(), new Object[] {paramObject});
            }
            catch (InvocationTargetException e)
            {
                e.fillInStackTrace();
                throw e.getTargetException();
            }
            catch (IllegalAccessException e)
            {
                e.fillInStackTrace();
                throw e;
            }
        }

        return paramObject;
    }
   
    /**
     * @return the name of the current test case being executed (it corresponds
     *         to the name of the test method with the "test" prefix removed.
     *         For example, for "testSomeTestOk" would return "someTestOk".
     */
    private String getCurrentTestName()
    {
        return JUnitVersionHelper.getTestCaseName(getDelegatedTest());       
    }
}
TOP

Related Classes of org.apache.cactus.internal.client.ClientTestCaseCaller

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.