Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.internal.client » [javadoc | source]
    1   /* 
    2    * ========================================================================
    3    * 
    4    * Copyright 2001-2004 The Apache Software Foundation.
    5    *
    6    * Licensed under the Apache License, Version 2.0 (the "License");
    7    * you may not use this file except in compliance with the License.
    8    * You may obtain a copy of the License at
    9    * 
   10    *   http://www.apache.org/licenses/LICENSE-2.0
   11    * 
   12    * Unless required by applicable law or agreed to in writing, software
   13    * distributed under the License is distributed on an "AS IS" BASIS,
   14    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    * See the License for the specific language governing permissions and
   16    * limitations under the License.
   17    * 
   18    * ========================================================================
   19    */
   20   package org.apache.cactus.internal.client;
   21   
   22   import java.lang.reflect.InvocationTargetException;
   23   import java.lang.reflect.Method;
   24   
   25   import junit.framework.Assert;
   26   import junit.framework.Test;
   27   
   28   import org.apache.cactus.Request;
   29   import org.apache.cactus.internal.util.JUnitVersionHelper;
   30   import org.apache.cactus.internal.util.TestCaseImplementChecker;
   31   import org.apache.cactus.spi.client.ResponseObjectFactory;
   32   import org.apache.cactus.spi.client.connector.ProtocolHandler;
   33   import org.apache.cactus.spi.client.connector.ProtocolState;
   34   import org.apache.commons.logging.Log;
   35   import org.apache.commons.logging.LogFactory;
   36   
   37   /**
   38    * Provides the ability to run common code before and after each test on the 
   39    * client side. All the methods provided are independent of any communication 
   40    * protocol between client side and server side (HTTP, JMS, etc). Any protocol 
   41    * dependent methods must be provided and implemented in the 
   42    * {@link ProtocolHandler} implementation class.
   43    *  
   44    * @version $Id: ClientTestCaseCaller.java,v 1.1 2004/05/22 11:34:47 vmassol Exp $
   45    */
   46   public class ClientTestCaseCaller extends Assert
   47   {
   48       /**
   49        * The prefix of a test method.
   50        */
   51       protected static final String TEST_METHOD_PREFIX = "test";
   52   
   53       /**
   54        * The prefix of a begin test method.
   55        */
   56       protected static final String BEGIN_METHOD_PREFIX = "begin";
   57   
   58       /**
   59        * The prefix of an end test method.
   60        */
   61       protected static final String END_METHOD_PREFIX = "end";
   62   
   63       /**
   64        * The name of the method that is called before each test on the client
   65        * side (if it exists).
   66        */
   67       protected static final String CLIENT_GLOBAL_BEGIN_METHOD = "begin";
   68   
   69       /**
   70        * The name of the method that is called after each test on the client
   71        * side (if it exists).
   72        */
   73       protected static final String CLIENT_GLOBAL_END_METHOD = "end";
   74   
   75       /**
   76        * The logger (only used on the client side).
   77        */
   78       private Log logger;
   79   
   80       /**
   81        * Pure JUnit Test Case that we are wrapping (if any)
   82        */
   83       private Test wrappedTest;
   84   
   85       /**
   86        * The test we are delegating for.
   87        */
   88       private Test delegatedTest;   
   89   
   90       /**
   91        * The protocol handler to use to execute the tests on the server side.
   92        */
   93       private ProtocolHandler protocolHandler;
   94   
   95       // Constructors ---------------------------------------------------------
   96       
   97       /**
   98        * @param theDelegatedTest the test we are delegating for
   99        * @param theWrappedTest the test being wrapped by this delegate (or null 
  100        *        if none)
  101        * @param theProtocolHandler the protocol handler to use to execute the 
  102        *        tests on the server side 
  103        */
  104       public ClientTestCaseCaller(Test theDelegatedTest, 
  105           Test theWrappedTest, ProtocolHandler theProtocolHandler)
  106       {        
  107           if (theDelegatedTest == null)
  108           {
  109               throw new IllegalStateException(
  110                   "The test object passed must not be null");
  111           }
  112   
  113           setDelegatedTest(theDelegatedTest); 
  114           setWrappedTest(theWrappedTest);
  115           this.protocolHandler = theProtocolHandler;
  116       }
  117   
  118       // Public methods -------------------------------------------------------
  119       
  120       /**
  121        * Execute begin and end methods and calls the different 
  122        * {@link ProtocolHandler} lifecycle methods to execute the test
  123        * on the server side.
  124        * 
  125        * Note that this method is overriden from the JUnit 
  126        * {@link junit.framework.TestCase} class in order to prevent JUnit from 
  127        * calling the {@link junit.framework.TestCase#setUp()} and
  128        * {@link junit.framework.TestCase#tearDown()} methods on the client side.
  129        * instead we are calling the server redirector proxy and the setup and
  130        * teardown methods will be executed on the server side.
  131        *
  132        * @exception Throwable if any error happens during the execution of
  133        *            the test
  134        */
  135       public void runTest() throws Throwable
  136       {
  137           Request request = this.protocolHandler.createRequest();
  138           
  139           // Call the set up and begin methods to fill the request object
  140           callGlobalBeginMethod(request);
  141           callBeginMethod(request);
  142   
  143           // Run the server test
  144           ProtocolState state = this.protocolHandler.runTest(
  145               getDelegatedTest(), getWrappedTest(), request);
  146           
  147           // Call the end method
  148           Object response = callEndMethod(request, 
  149               this.protocolHandler.createResponseObjectFactory(state));
  150   
  151           // call the tear down method
  152           callGlobalEndMethod(request, 
  153               this.protocolHandler.createResponseObjectFactory(state), 
  154               response);
  155   
  156           this.protocolHandler.afterTest(state);
  157       }
  158   
  159       /**
  160        * @return The logger used by the <code>TestCase</code> class and
  161        *         subclasses to perform logging.
  162        */
  163       public final Log getLogger()
  164       {
  165           return this.logger;
  166       }
  167   
  168       /**
  169        * Perform client side initializations before each test, such as
  170        * re-initializating the logger and printing some logging information.
  171        */
  172       public void runBareInit()
  173       {
  174           // We make sure we reinitialize The logger with the name of the
  175           // current extending class so that log statements will contain the
  176           // actual class name (that's why the logged instance is not static).
  177           this.logger = LogFactory.getLog(this.getClass());
  178   
  179           // Mark beginning of test on client side
  180           getLogger().debug("------------- Test: " + this.getCurrentTestName());
  181       }
  182   
  183       /**
  184        * Call the test case begin method.
  185        *
  186        * @param theRequest the request object to pass to the begin method.
  187        * @exception Throwable any error that occurred when calling the begin
  188        *            method for the current test case.
  189        */
  190       public void callBeginMethod(Request theRequest) throws Throwable
  191       {
  192           callGenericBeginMethod(theRequest, getBeginMethodName());
  193       }
  194   
  195       /**
  196        * Call the test case end method
  197        *
  198        * @param theRequest the request data that were used to open the
  199        *                   connection.
  200        * @param theResponseFactory the factory to use to return response objects.
  201        * @return the created Reponse object
  202        * @exception Throwable any error that occurred when calling the end method
  203        *         for the current test case.
  204        */
  205       public Object callEndMethod(Request theRequest, 
  206           ResponseObjectFactory theResponseFactory) throws Throwable
  207       {
  208           return callGenericEndMethod(theRequest, theResponseFactory,
  209               getEndMethodName(), null);
  210       }
  211   
  212       /**
  213        * Call the global begin method. This is the method that is called before
  214        * each test if it exists. It is called on the client side only.
  215        *
  216        * @param theRequest the request object which will contain data that will
  217        *        be used to connect to the Cactus server side redirectors.
  218        * @exception Throwable any error that occurred when calling the method
  219        */
  220       public void callGlobalBeginMethod(Request theRequest) throws Throwable
  221       {
  222           callGenericBeginMethod(theRequest, CLIENT_GLOBAL_BEGIN_METHOD);
  223       }
  224   
  225       /**
  226        * Call the client tear down up method if it exists.
  227        *
  228        * @param theRequest the request data that were used to open the
  229        *                   connection.
  230        * @param theResponseFactory the factory to use to return response objects.
  231        * @param theResponse the Response object if it exists. Can be null in
  232        *        which case it is created from the response object factory
  233        * @exception Throwable any error that occurred when calling the method
  234        */
  235       private void callGlobalEndMethod(Request theRequest, 
  236           ResponseObjectFactory theResponseFactory, Object theResponse) 
  237           throws Throwable
  238       {
  239           callGenericEndMethod(theRequest, theResponseFactory,
  240               CLIENT_GLOBAL_END_METHOD, theResponse);
  241       }
  242       
  243       // Private methods ------------------------------------------------------
  244       
  245       /**
  246        * @param theWrappedTest the pure JUnit test that we need to wrap 
  247        */
  248       private void setWrappedTest(Test theWrappedTest)
  249       {
  250           this.wrappedTest = theWrappedTest;
  251       }
  252   
  253       /**
  254        * @param theDelegatedTest the test we are delegating for
  255        */
  256       private void setDelegatedTest(Test theDelegatedTest)
  257       {
  258           this.delegatedTest = theDelegatedTest;
  259       }
  260   
  261       /**
  262        * @return the wrapped JUnit test
  263        */
  264       private Test getWrappedTest()
  265       {
  266           return this.wrappedTest;
  267       }
  268   
  269       /**
  270        * @return the test we are delegating for
  271        */
  272       private Test getDelegatedTest()
  273       {
  274           return this.delegatedTest;
  275       }
  276   
  277       /**
  278        * @return the test on which we will operate. If there is a wrapped
  279        *         test then the returned test is the wrapped test. Otherwise we
  280        *         return the delegated test.
  281        */
  282       private Test getTest()
  283       {
  284           Test activeTest;
  285           if (getWrappedTest() != null)
  286           {
  287               activeTest = getWrappedTest();
  288           }
  289           else
  290           {
  291               activeTest = getDelegatedTest();
  292           }
  293           return activeTest;
  294       }
  295   
  296       /**
  297        * @return the name of the test method to call without the
  298        *         TEST_METHOD_PREFIX prefix
  299        */
  300       private String getBaseMethodName()
  301       {
  302           // Sanity check
  303           if (!getCurrentTestName().startsWith(TEST_METHOD_PREFIX))
  304           {
  305               throw new RuntimeException("bad name ["
  306                   + getCurrentTestName()
  307                   + "]. It should start with ["
  308                   + TEST_METHOD_PREFIX + "].");
  309           }
  310   
  311           return getCurrentTestName().substring(
  312               TEST_METHOD_PREFIX.length());
  313       }
  314   
  315       /**
  316        * @return the name of the test begin method to call that initialize the
  317        *         test by initializing the <code>WebRequest</code> object
  318        *         for the test case.
  319        */
  320       private String getBeginMethodName()
  321       {
  322           return BEGIN_METHOD_PREFIX + getBaseMethodName();
  323       }
  324   
  325       /**
  326        * @return the name of the test end method to call when the test has been
  327        *         run on the server. It can be used to verify returned headers,
  328        *         cookies, ...
  329        */
  330       private String getEndMethodName()
  331       {
  332           return END_METHOD_PREFIX + getBaseMethodName();
  333       }
  334   
  335       /**
  336        * Call a begin method which takes Cactus WebRequest as parameter
  337        *
  338        * @param theRequest the request object which will contain data that will
  339        *        be used to connect to the Cactus server side redirectors.
  340        * @param theMethodName the name of the begin method to call
  341        * @exception Throwable any error that occurred when calling the method
  342        */
  343       private void callGenericBeginMethod(Request theRequest, 
  344           String theMethodName) throws Throwable
  345       {
  346           // First, verify if a begin method exist. If one is found, verify if
  347           // it has the correct signature. If not, send a warning.
  348           Method[] methods = getTest().getClass().getMethods();
  349   
  350           for (int i = 0; i < methods.length; i++)
  351           {
  352               if (methods[i].getName().equals(theMethodName))
  353               {
  354                   TestCaseImplementChecker.checkAsBeginMethod(methods[i]);
  355   
  356                   try
  357                   {
  358                       methods[i].invoke(getTest(), new Object[] {theRequest});
  359   
  360                       break;
  361                   }
  362                   catch (InvocationTargetException e)
  363                   {
  364                       e.fillInStackTrace();
  365                       throw e.getTargetException();
  366                   }
  367                   catch (IllegalAccessException e)
  368                   {
  369                       e.fillInStackTrace();
  370                       throw e;
  371                   }
  372               }
  373           }
  374       }
  375   
  376       /**
  377        * Call the global end method. This is the method that is called after
  378        * each test if it exists. It is called on the client side only.
  379        *
  380        * @param theRequest the request data that were used to open the
  381        *        connection.
  382        * @param theResponseFactory the factory to use to return response objects.
  383        * @param theMethodName the name of the end method to call
  384        * @param theResponse the Response object if it exists. Can be null in
  385        *        which case it is created from the response object factory
  386        * @return the created Reponse object
  387        * @exception Throwable any error that occurred when calling the end method
  388        *            for the current test case.
  389        */
  390       private Object callGenericEndMethod(Request theRequest,
  391           ResponseObjectFactory theResponseFactory, String theMethodName, 
  392           Object theResponse) throws Throwable
  393       {
  394           Method methodToCall = null;
  395           Object paramObject = null;
  396   
  397           Method[] methods = getTest().getClass().getMethods();
  398   
  399           for (int i = 0; i < methods.length; i++)
  400           {
  401               if (methods[i].getName().equals(theMethodName))
  402               {
  403                   TestCaseImplementChecker.checkAsEndMethod(methods[i]);
  404   
  405                   paramObject = theResponse;
  406   
  407                   if (paramObject == null)
  408                   {
  409                       Class[] parameters = methods[i].getParameterTypes();
  410                       try
  411                       {
  412                           paramObject = theResponseFactory.getResponseObject(
  413                               parameters[0].getName(), theRequest);
  414                       }
  415                       catch (ClientException e)
  416                       {
  417                           throw new ClientException("The method ["
  418                               + methods[i].getName() 
  419                               + "] has a bad parameter of type ["
  420                               + parameters[0].getName() + "]", e);
  421                       }
  422                   }
  423   
  424                   // Has a method to call already been found ?
  425                   if (methodToCall != null)
  426                   {
  427                       fail("There can only be one method ["
  428                          + methods[i].getName() + "] per test case. "
  429                          + "Test case [" + this.getCurrentTestName()
  430                          + "] has two at least !");
  431                   }
  432   
  433                   methodToCall = methods[i];
  434               }
  435           }
  436   
  437           if (methodToCall != null)
  438           {
  439               try
  440               {
  441                   methodToCall.invoke(getTest(), new Object[] {paramObject});
  442               }
  443               catch (InvocationTargetException e)
  444               {
  445                   e.fillInStackTrace();
  446                   throw e.getTargetException();
  447               }
  448               catch (IllegalAccessException e)
  449               {
  450                   e.fillInStackTrace();
  451                   throw e;
  452               }
  453           }
  454   
  455           return paramObject;
  456       }
  457       
  458       /**
  459        * @return the name of the current test case being executed (it corresponds
  460        *         to the name of the test method with the "test" prefix removed.
  461        *         For example, for "testSomeTestOk" would return "someTestOk".
  462        */
  463       private String getCurrentTestName()
  464       {
  465           return JUnitVersionHelper.getTestCaseName(getDelegatedTest());        
  466       }
  467   }

Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.internal.client » [javadoc | source]