jakarta-cactus-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Christopher Lenz <cml...@gmx.de>
Subject Ant integration proposal - Summary
Date Fri, 09 May 2003 23:24:40 GMT
Hi folks,

given that it's a bit hard to follow the rapid changes I have been doing 
lately in a branch of the Cactus CVS repository, I thought I'd write a 
summary that provides some context and information on the proposed Ant 
integration. This is rather long, so you might prefer to print it out 
and lean back while reading :-)

          |               Background                 |

No released version of Cactus has a real Ant integration layer. What 
exists is the well known <runservertests> task and a handful of build 
file fragments that can start and stop specific containers. The 
<runservertests> task exists because it makes it easier to manage the 
startup/shutdown of containers before/after the Cactus tests are run. In 
fact, since Ant 1.5 the same thing can be accomplished using a smart 
combination of the <waitfor>/<sequential>/<parallel> tasks, although 
that's a bit involved.

One problem with this situation is that the <runservertests> task 
operates on a relatively low level. It only provides a basic mechanism 
to run the in-container tests, without providing a good abstraction over 
what's happening. In addition, it implicitly uses the core <antcall> 
task to start/stop the server and run the tests, which results in build 
files that tend to be procedural (as opposed to declarative, what Ant 
build files are supposed to be, ideally). The use of <antcall> also 
imposes a lot of runtime overhead on a build, because a target called 
this way is executed as if it was directly invoked from the 
command-line, i.e. all the targets it depends on are also executed. Thus 
it is quite hard to achieve a well structured build with minimized build 
time and a clear dependancy graph when using <runservertests>.

The other problem is that the build file fragments were made available 
from the Cactus servlet-sample, and needed to be copied -- possibly 
modified -- into a project that wanted to use Cactus via Ant. Obviously 
this is a maintenance nightmare and requires a lot of work from 
Cactus/Ant users.

          |            Recent Development            |

A few months ago, Vincent moved the build file fragments as well as the 
<runservertests> task that were a bit scattered throughout the Cactus 
CVS into a new "real" Ant integration module, and cleaned it all up. The 
intent was to make it unnecessary for the user to copy/integrate the 
stuff from the servlet-sample into her own projects. Basically, it 
should be possible to just do:

   <ant dir="${cactus.install.dir}" target="test.tomcat4x">
     <property name="cactus.home.tomcat4x"/>

and have the tests run against Tomcat 4.x. Configuration is done via Ant 
properties and references. For example, there's a property that defines 
the source directory of the test code, a property for the port on which 
to run the container, etc etc. Later in the game an Ant task, 
<webxmlmerge>, was added to merge two deployment descriptors, used for 
extending a standard web.xml with the definitions needed for the Cactus 

          |                 Proposal                 |

When I finally had some time to seriously play with this new integration 
module, I found a couple of shortcomings as well as a general -- or call 
it philosophical -- conflict with the way third-party applications and 
framework usually integrate into Ant. The approach chosen seemed closer 
to the plug-in model used by Maven. What I would have wanted was a JAR 
containing a couple of tasks that I could use to easily integrate 
Cactus-based tests into an Ant build. These tasks would hide as much as 
possible from the the complex activities required to get the tests 
running, but still provide great flexibility and control over how the 
tests are executed.

Thus I made a proposal for a different kind of Ant integration [1]. The 
proposed integration should provide full-featured tasks to accomplish a 
clean integration of Cactus with Ant. The proposal has been developed in 
a branch of the Cactus CVS (CACTUS_14_ANT_BRANCH), and has reached a 
level of relative maturity by now. In the following, unless I explicitly 
talk about the "old" Ant integration, I'm referring to the integration 
module as implemented in the proposal branch.

          |                Ant Tasks                 |

The Ant integration attempts to provide solutions for two areas that are 
usually difficult, error-prone and/or just annoying to implement currently:

  - Cactifying a web-application

    With "cactification" we mean enhancing an existing, plain
    web-application with the redirectors and resources needed to run
    Cactus tests. This includes adding the definitions of the Cactus
    test redirectors to the deployment descriptor of the web-app, as
    well as adding the libraries required by Cactus on the server-side,
    and adding the JSP file for the JSP redirector.

    For this purpose, the Ant ingegration defines a <cactify> task,
    which can be used like this:

      <cactify srcfile="myapp.war" destfile="cactustest.war">
        <servletredirector mapping="/test/ServletRedirector"/>
        <jspredirector mapping="/test/JspRedirector"/>
        <classes dir="${test.classes.dir}" includes="**/*.class"/>

    As you can probably see, <cactify> takes an existing WAR file as
    input and generates a new, cactified WAR file. It automatically adds
    the JARs required by Cactus on the server side to the cactified
    WAR (they need to be on the task's classpath for this to work,
    though). It also adds the jspRedirector.jsp file to the generated
    WAR automatically. By default, the redirector definitions are added
    to the resulting web.xml with the default mappings, but you can
    override the mapping on a per-redirector basis.

    In fact, the <cactify> task extends the core <war> task, so you can
    specify arbitrary files to be included in the cactified WAR by using
    nested <classes>, <lib>, <fileset>, <metainf> or <webinf>
    This feature is used in the above example to add the test classes to
    the WAR.

  - Running the Cactus tests

    There are two distinct parts to running Cactus tests: first, the
    container to test against needs to be running, second, the tests need
    to be executed by some JUnit test runner. Ant already provides an
    optional, much used, <junit> task for the latter. In the past, it was
    usually used in combination with the <runservertests> task and a
    couple of targets that startup and shutdown containers, with all the
    problems discussed further above.

    The proposed integration module provides a custom <cactus> task that
    extends the <junit> task with provisions for in-container tests.
    Specifically, the <cactus> task takes a WAR file as input and allows
    the specification of a set of containers to run the tests against.

    For example, to run some tests against Tomcat 4.x and Resin 2.x the
    <cactus> task could be used like this:

      <cactus warfile="cactustest.war" failureproperty="tests.failed">
          <tomcat4x dir="${tomcat4x.home}" port="8080"/>
          <resinx dir="${resin2x.home}" port="8080"/>
        <formatter type="brief" usefile="no"/>
          <fileset dir="${src.test.dir}" includes="**/*Test.java"/>

    Simple, no? And all in a single target. But the <cactus> task
    provides more flexibility, too:

      <cactus ...>
        <containerset timeout="60000">
          <generic port="8080" todir="${test.reports.dir}/foobar">
              <echo>Starting Foobar</echo>
              <java classname="foo.bar.Main" fork="yes">
                <arg value="start"/>
                <arg value="-port"/>
                <arg value="8080"/>
              <echo>Stopping Foobar</echo>
              <java classname="foo.bar.Main" fork="yes">
                <arg value="stop"/>

     So you can either test against one of the containers with built-in
     support, or against some exotic or just unsupported container.
     Currently, the <cactus> task supports the following containers:

       - Apache Tomcat 3.x
       - Apache Tomcat 4.x
       - Apache Tomcat 5.x
       - Caucho Resin 2.x
       - Orion 1.x and 2.x
       - JBoss 3.x (limited support)

     (I could use some help with the WebLogic support)

     As noted above, the <cactus> task takes a WAR file as input. Apart
     from that WAR file being passed to the individual containers for
     deployment, it is also analyzed to extract the correct settings for
     the Cactus system properties. So, the mappings of the test
     redirectors are retrieved from the web.xml in the test WAR and
     automatically setup as the cactus.XxxRedirectorName system
     properties. The cactus.contextURL is assembled from the name of
     the WAR file and the specified port.

          |                 Summary                  |

The proposed Ant integration module I just tried to describe has quite a 
few advantages over the current integration IMHO (naturally), which I'll 
try to summarize here. If you're the manager type and read all the stuff 
above, I'm pleased to announce that it would have been enough to read 
this section ;-)

  - The proposal provides a kind of integration with Ant that Ant users
    are already very familiar with. It is the standard way to integrate
    with Ant builds: by providing tasks that need to be <taskdef>'d.

  - It does not require the user to "install" anything, or copy files
    into their project, except for the Cactus JARs.

  - It's not necessary to use <antcall> (explicitly or implicitly), which
    makes for shorter build execution times, cleaner dependancy graphs
    and more digestable log ouput from the build. When you execute the
    Cactus tests, you usually stay within a single target.

  - Running the tests is less error-prone, because the web-app archive
    can be automatically cactified, and the <cactus> task will
    automatically extract the correct settings for the Cactus system

  - Output from the containers can be redirected into a file, thus making
    the actual build output easier to read.

  - By using the 'proxyport' attribute of the <containerset> element, a
    proxy application can be inserted between the client-side and the
    server-side of Cactus tests, thus making it simpler to track down
    non-obvious failures.

  - Through the <generic> container element, we still provide all the
    flexibility of the <runservertests> task.

  - There are more (albeit still not enough) unit tests :-)

If you've come this far, it's probably time to grab a box of cookies, a 
coffee or a cigarette, depending on your preferences and your current 
environment. Any feedback would be most welcome. Thanks for reading!

[1] http://marc.theaimsgroup.com/?l=cactus-dev&m=105057096209634&w=2

Christopher Lenz
/=/ cmlenz at gmx.de

View raw message