2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

Clover coverage report - Cactus 1.8dev for J2EE API 1.3
Coverage timestamp: Sun Mar 26 2006 18:50:18 BRT
file stats: LOC: 526   Methods: 17
NCLOC: 306   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
CactusTestTask.java 0% 0% 0% 0%
coverage
 1   
 /* 
 2   
  * ========================================================================
 3   
  * 
 4   
  * Copyright 2003-2005 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.integration.ant;
 21   
 
 22   
 import java.util.Enumeration;
 23   
 import java.util.PropertyResourceBundle;
 24   
 import java.util.ResourceBundle;
 25   
 import java.io.File;
 26   
 import java.io.FileInputStream;
 27   
 import java.io.IOException;
 28   
 import java.io.InputStream;
 29   
 import java.net.HttpURLConnection;
 30   
 import java.net.URL;
 31   
 import java.net.MalformedURLException;
 32   
 
 33   
 import org.apache.cactus.integration.ant.deployment.DeployableFile;
 34   
 import org.apache.cactus.integration.ant.deployment.EarParser;
 35   
 import org.apache.cactus.integration.ant.deployment.WarParser;
 36   
 import org.apache.tools.ant.BuildException;
 37   
 import org.apache.tools.ant.Project;
 38   
 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask;
 39   
 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
 40   
 import org.apache.tools.ant.types.Path;
 41   
 import org.apache.tools.ant.types.Environment.Variable;
 42   
 
 43   
 /**
 44   
  * An Ant task that extends the optional JUnit task to provide support for
 45   
  * in-container testing. 
 46   
  * This class is a refactor of CactusTask v.133 and
 47   
  * RunContainerTask v.133 to use cargo
 48   
  * 
 49   
  * @version $Id: CactusTestTask.java 239202 2005-08-11 18:48:07Z felipeal $
 50   
  * @since 1.8
 51   
  */
 52   
 public class CactusTestTask extends JUnitTask
 53   
 {
 54   
     /**
 55   
      * The servlet port element.
 56   
      */
 57   
     private String servletPort;
 58   
 
 59   
     /**
 60   
      * The testreportDir element.
 61   
      */
 62   
     private File toDir;
 63   
 
 64   
     /**
 65   
      * The log element.
 66   
      */
 67   
     private File logs;
 68   
 
 69   
     /**
 70   
      * The archive that contains the enterprise application that should be
 71   
      * tested.
 72   
      */
 73   
     private File earFile;
 74   
 
 75   
     /**
 76   
      * The archive that contains the web-app that is ready to be tested.
 77   
      */
 78   
     private File warFile;
 79   
 
 80   
     /**
 81   
      * The deployable file.
 82   
      */
 83   
     private DeployableFile deployableFile;
 84   
 
 85   
     /**
 86   
      * Additional classpath entries for the classpath that will be used to start
 87   
      * the containers.
 88   
      */
 89   
     private Path additionalClasspath;
 90   
     
 91   
     /**
 92   
      * Timeout after trying to connect(in ms).
 93   
      */
 94   
     private long timeout = 180000;
 95   
     
 96   
     /**
 97   
      * The time interval in milliseconds to sleep between polling the container.
 98   
      */
 99   
     private long checkInterval = 500;
 100   
 
 101   
 
 102   
     // Constructors -----------------------------------------------------------
 103   
 
 104   
     /**
 105   
      * Constructor.
 106   
      * 
 107   
      * @throws Exception
 108   
      *             If the constructor of JUnitTask throws an exception
 109   
      */
 110  0
     public CactusTestTask() throws Exception
 111   
     {
 112  0
         super();
 113   
     }
 114   
 
 115   
     // Public Methods -------------------------------------------------------
 116   
 
 117   
     /**
 118   
      * @see org.apache.tools.ant.Task#init()
 119   
      */
 120  0
     public void init()
 121   
     {
 122  0
         super.init();
 123   
 
 124  0
         addClasspathEntry("/org/apache/cactus/ServletTestCase.class");
 125  0
         addClasspathEntry("/org/apache/commons/logging/Log.class");
 126  0
         addClasspathEntry("/org/apache/commons/httpclient/HttpClient.class");
 127   
     }
 128   
 
 129   
     /**
 130   
      * @see org.apache.tools.ant.Task#execute()
 131   
      */
 132  0
     public void execute() throws BuildException
 133   
     {
 134  0
         if (this.servletPort == null)
 135   
         {
 136  0
              log("Using default servletport=8080", Project.MSG_INFO);
 137  0
              servletPort = "8080";
 138   
 
 139   
         }
 140  0
         if (this.toDir == null)
 141   
         {
 142  0
             throw new BuildException(
 143   
                     "You must specify the test report directory");
 144   
 
 145   
         }
 146  0
         if ((this.warFile != null) && (this.earFile != null))
 147   
         {
 148  0
             throw new BuildException(
 149   
                     "You must specify either the [warfile] or "
 150   
                             + "the [earfile] attribute but not both");
 151   
         }
 152   
 
 153   
         // Parse deployment descriptors for WAR or EAR files
 154  0
         if (this.warFile != null)
 155   
         {
 156  0
             deployableFile = WarParser.parse(this.warFile);
 157   
         }
 158   
         else
 159   
         {
 160  0
             deployableFile = EarParser.parse(this.earFile);
 161   
         }
 162   
 
 163  0
         addRedirectorNameProperties();
 164   
 
 165  0
         Variable contextUrlVar = new Variable();
 166  0
         contextUrlVar.setKey("cactus.contextURL");
 167  0
         contextUrlVar.setValue("http://localhost:" + servletPort
 168   
             + "/" + deployableFile.getTestContext());
 169  0
         addSysproperty(contextUrlVar);
 170   
 
 171   
         //Setup logs
 172  0
         setupLogs();
 173   
         //Run the test cases
 174  0
         testInContainer();
 175   
     }
 176   
 
 177   
     /**
 178   
      * Extracts the redirector mappings from the deployment descriptor and sets
 179   
      * the corresponding system properties.
 180   
      */
 181  0
     private void addRedirectorNameProperties()
 182   
     {
 183  0
         String filterRedirectorMapping = deployableFile
 184   
                 .getFilterRedirectorMapping();
 185  0
         if (filterRedirectorMapping != null)
 186   
         {
 187  0
             Variable filterRedirectorVar = new Variable();
 188  0
             filterRedirectorVar.setKey("cactus.filterRedirectorName");
 189  0
             filterRedirectorVar.setValue(filterRedirectorMapping
 190   
                     .substring(1));
 191  0
             addSysproperty(filterRedirectorVar);
 192   
         }
 193   
         else
 194   
         {
 195  0
             log("No mapping of the filter redirector found",
 196   
                     Project.MSG_VERBOSE);
 197   
         }
 198   
 
 199  0
         String jspRedirectorMapping = deployableFile.getJspRedirectorMapping();
 200  0
         if (jspRedirectorMapping != null)
 201   
         {
 202  0
             Variable jspRedirectorVar = new Variable();
 203  0
             jspRedirectorVar.setKey("cactus.jspRedirectorName");
 204  0
             jspRedirectorVar.setValue(jspRedirectorMapping.substring(1));
 205  0
             addSysproperty(jspRedirectorVar);
 206   
         }
 207   
         else
 208   
         {
 209  0
             log("No mapping of the JSP redirector found",
 210   
                     Project.MSG_VERBOSE);
 211   
         }
 212   
 
 213  0
         String servletRedirectorMapping = deployableFile
 214   
                 .getServletRedirectorMapping();
 215  0
         if (servletRedirectorMapping != null)
 216   
         {
 217  0
             Variable servletRedirectorVar = new Variable();
 218  0
             servletRedirectorVar.setKey("cactus.servletRedirectorName");
 219  0
             servletRedirectorVar.setValue(servletRedirectorMapping
 220   
                     .substring(1));
 221  0
             addSysproperty(servletRedirectorVar);
 222   
         }
 223   
         else
 224   
         {
 225  0
             throw new BuildException("The WAR has not been cactified");
 226   
         }
 227   
 
 228   
     }
 229   
     
 230   
 
 231   
     /**
 232   
      * Executes the unit tests in the given container.
 233   
      *  
 234   
      */
 235  0
     private void testInContainer()
 236   
     {
 237  0
         URL testURL = null;
 238  0
         try
 239   
         {
 240  0
             testURL = new URL("http://localhost:" + servletPort 
 241   
                 + "/" +  deployableFile.getTestContext()
 242   
                 + deployableFile.getServletRedirectorMapping()
 243   
                 + "?Cactus_Service=RUN_TEST");
 244   
             
 245   
         }
 246   
         catch (MalformedURLException e)
 247   
         {
 248  0
             throw new BuildException("Invalid URL format: " + testURL);
 249   
         }
 250   
         //Ping the container
 251   
         //Continuously try calling the test URL until it succeeds or
 252   
         // until a timeout is reached (we then throw a build exception).
 253  0
         long startTime = System.currentTimeMillis();
 254  0
         int responseCode = -1;
 255  0
         do
 256   
         {
 257  0
             if ((System.currentTimeMillis() - startTime) > this.timeout)
 258   
             {
 259  0
                 throw new BuildException("Failed to start the container after "
 260   
                     + "more than [" + this.timeout + "] ms. Trying to connect "
 261   
                     + "to the [" + testURL + "] test URL yielded a ["
 262   
                     + responseCode + "] error code. Please run in debug mode "
 263   
                     + "for more details about the error.");
 264   
             }
 265  0
             sleep(this.checkInterval);
 266   
             
 267  0
             responseCode = testConnectivity(testURL);
 268  0
         } while (!isAvailable(responseCode));
 269   
 
 270   
         
 271  0
         log("Starting up tests", Project.MSG_VERBOSE);
 272  0
         try
 273   
         {
 274   
 
 275  0
             Enumeration tests = getIndividualTests();
 276  0
             while (tests.hasMoreElements())
 277   
             {
 278  0
                 JUnitTest test = (JUnitTest) tests.nextElement();
 279  0
                 if (test.shouldRun(getProject()))
 280   
                 {
 281  0
                     test.setTodir(toDir);
 282  0
                     execute(test);
 283   
                 }
 284   
             }
 285   
         }
 286   
         finally
 287   
         {
 288  0
             log("Finishing tests", Project.MSG_VERBOSE);
 289   
 
 290   
         }
 291   
     }
 292   
 
 293   
     /**
 294   
      * Sets the enterprise application archive that will be tested. It must
 295   
      * already contain the test-cases and the required libraries as a web
 296   
      * module.
 297   
      * 
 298   
      * @param theEarFile
 299   
      *            The EAR file to set
 300   
      */
 301  0
     public final void setEarFile(File theEarFile)
 302   
     {
 303  0
         if (this.warFile != null)
 304   
         {
 305  0
             throw new BuildException(
 306   
                     "You may only specify one of [earfile] and [warfile]");
 307   
         }
 308  0
         this.earFile = theEarFile;
 309   
     }
 310   
 
 311   
     /**
 312   
      * Sets the web application archive that will be tested. It must already
 313   
      * contain the test-cases and the required libraries.
 314   
      * 
 315   
      * @param theWarFile
 316   
      *            The WAR file to set
 317   
      */
 318  0
     public final void setWarFile(File theWarFile)
 319   
     {
 320  0
         if (this.earFile != null)
 321   
         {
 322  0
             throw new BuildException(
 323   
                     "You may only specify one of [earfile] and [warfile]");
 324   
         }
 325  0
         this.warFile = theWarFile;
 326   
     }
 327   
 
 328   
     /**
 329   
      * Sets the context url that will be tested.
 330   
      * 
 331   
      * @param theServletPort
 332   
      *            The servlet port
 333   
      */
 334  0
     public final void setServletPort(String theServletPort)
 335   
     {
 336  0
         this.servletPort = theServletPort;
 337   
     }
 338   
 
 339   
     /**
 340   
      * Sets the web application archive that should be cactified.
 341   
      * 
 342   
      * @param theToDir
 343   
      *            The test report to set
 344   
      */
 345  0
     public final void setToDir(File theToDir)
 346   
     {
 347  0
         this.toDir = theToDir;
 348   
     }
 349   
     /**
 350   
      * Sets the web application archive that should be cactified.
 351   
      * 
 352   
      * @param theLogs
 353   
      *            Different logs define
 354   
      */
 355  0
     public final void setLogs(File theLogs)
 356   
     {
 357  0
         this.logs = theLogs;
 358   
     }
 359   
     // Private Methods ---------------------------------------------------------
 360   
 
 361   
     /**
 362   
      * Tests whether we are able to connect to the HTTP server identified by the
 363   
      * specified URL.
 364   
      * 
 365   
      * @param theUrl The URL to check
 366   
      * @return the HTTP response code or -1 if no connection could be 
 367   
      *         established
 368   
      */
 369  0
     private int testConnectivity(URL theUrl)
 370   
     {
 371  0
         int code = -1;
 372  0
         HttpURLConnection connection = null;
 373  0
         try
 374   
         {
 375  0
             connection = (HttpURLConnection) theUrl.openConnection();
 376  0
             connection.setRequestProperty("Connection", "close");
 377  0
             connection.connect();
 378  0
             code = connection.getResponseCode();
 379  0
             readFully(connection);
 380  0
             connection.disconnect();
 381   
         }
 382   
         catch (IOException e)
 383   
         {
 384  0
             log("Get status = " + code  
 385   
                     + " when trying [" + theUrl + "]", Project.MSG_DEBUG);
 386   
 
 387   
         }
 388  0
         return code;
 389   
     }
 390   
 
 391   
 
 392   
     /**
 393   
      * Tests whether an HTTP return code corresponds to a valid connection
 394   
      * to the test URL or not. Success is 200 up to but excluding 300.
 395   
      * 
 396   
      * @param theCode the HTTP response code to verify
 397   
      * @return <code>true</code> if the test URL could be called without error,
 398   
      *         <code>false</code> otherwise
 399   
      */
 400  0
     private boolean isAvailable(int theCode)
 401   
     {
 402  0
         boolean result;
 403  0
         if ((theCode != -1) && (theCode < 300)) 
 404   
         {
 405  0
             result = true;            
 406   
         }
 407   
         else
 408   
         {
 409  0
             result = false;
 410   
         }
 411  0
         return result;
 412   
     }
 413   
 
 414   
     /**
 415   
      * Retrieves the server name of the container.
 416   
      * 
 417   
      * @param theUrl The URL to retrieve
 418   
      * @return The server name, or <code>null</code> if the server name could 
 419   
      *         not be retrieved
 420   
      */
 421  0
     private String retrieveServerName(URL theUrl)
 422   
     {
 423  0
         String retVal = null;
 424  0
         try
 425   
         {
 426  0
             HttpURLConnection connection = 
 427   
                 (HttpURLConnection) theUrl.openConnection();
 428  0
             connection.connect();
 429  0
             retVal = connection.getHeaderField("Server");
 430  0
             connection.disconnect();
 431   
         }
 432   
         catch (IOException e)
 433   
         {
 434  0
             log("Could not get server name from [" 
 435   
                 + theUrl + "]", Project.MSG_DEBUG);
 436   
         }
 437  0
         return retVal;
 438   
     }
 439   
 
 440   
     /**
 441   
      * Fully reads the input stream from the passed HTTP URL connection to
 442   
      * prevent (harmless) server-side exception.
 443   
      *
 444   
      * @param theConnection the HTTP URL connection to read from
 445   
      * @exception IOException if an error happens during the read
 446   
      */
 447  0
     static void readFully(HttpURLConnection theConnection)
 448   
                    throws IOException
 449   
     {
 450   
         // Only read if there is data to read ... The problem is that not
 451   
         // all servers return a content-length header. If there is no header
 452   
         // getContentLength() returns -1. It seems to work and it seems
 453   
         // that all servers that return no content-length header also do
 454   
         // not block on read() operations!
 455  0
         if (theConnection.getContentLength() != 0)
 456   
         {
 457  0
             byte[] buf = new byte[256];
 458  0
             InputStream in = theConnection.getInputStream();
 459  0
             while (in.read(buf) != -1)
 460   
             {
 461   
                 // Make sure we read all the data in the stream
 462   
             }
 463   
         }
 464   
     }
 465   
 
 466   
     /**
 467   
      * Pauses the current thread for the specified amount.
 468   
      *
 469   
      * @param theMs The time to sleep in milliseconds
 470   
      * @throws BuildException If the sleeping thread is interrupted
 471   
      */
 472  0
     private void sleep(long theMs) throws BuildException
 473   
     {
 474  0
         try
 475   
         {
 476  0
             Thread.sleep(theMs);
 477   
         }
 478   
         catch (InterruptedException e)
 479   
         {
 480  0
             throw new BuildException("Interruption during sleep", e);
 481   
         }
 482   
     }
 483   
     /**
 484   
      * @param theTimeout the timeout after which we stop trying to call the test
 485   
      *        URL.
 486   
      */
 487  0
     public void setTimeout(long theTimeout)
 488   
     {
 489  0
         this.timeout = theTimeout;
 490   
     }
 491   
     /**
 492   
      * Set up the logs
 493   
      */
 494  0
     public void setupLogs()
 495   
     {
 496   
        
 497  0
         if (this.logs == null)
 498   
         {
 499  0
             throw new BuildException("Missing 'logs' attribute");
 500   
         }
 501   
         
 502  0
         ResourceBundle bundle = null;
 503  0
         try
 504   
         {
 505  0
             bundle = new PropertyResourceBundle(
 506   
                 new FileInputStream(this.logs));
 507   
         } 
 508   
         catch (IOException e)
 509   
         {
 510  0
             throw new BuildException("Failed to load properties "
 511   
                 + "file [" + this.logs + "]");
 512   
         }
 513  0
         Enumeration keys = bundle.getKeys();
 514  0
         while (keys.hasMoreElements())
 515   
         {
 516  0
             String key = (String) keys.nextElement();
 517  0
             Variable var = new Variable();
 518  0
             var.setKey(key);
 519  0
             var.setValue(bundle.getString(key));        
 520  0
             super.addSysproperty(var);
 521   
             
 522   
         }
 523   
        
 524   
     }
 525   
 }
 526