<?xml version="1.0"?>

<!--
 * ========================================================================
 * 
 * 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.
 * 
 * ========================================================================
-->

<document id="faq">

  <properties>
    <title>FAQ</title>
  </properties>

  <body>

    <section title="FAQ Content">

      <p>
        Please also make sure you visit the
        <a href="ext:cactus_wiki_faq">online user FAQ</a> on our 
        <a href="ext:cactus_wiki">Wiki</a>.
      </p>
      
      <ul>
        <li>
          <jump anchor="faq_cant_find_resource">"Can't find resource for cactus" error
          message</jump>
        </li>
        <li>
          <jump anchor="faq_webxml_test_prod">How can I have a web.xml that is valid both for
          testing and for production?</jump>
        </li>
        <li>
          <jump anchor="faq_stream_corrupted_exception">I'm getting a
          <code>java.io.StreamCorruptedException: InputStream does not contain a
          serialized object</code> error. What does it mean?</jump>
        </li>
        <li>
          <jump anchor="faq_chaining_requests">How can I test the chaining of several HTTP
          requests?</jump>
        </li>
        <li>
          <jump anchor="faq_runservertests_hangs">The &lt;runservertests&gt; Ant task hangs when 
          my server is started</jump>
        </li>
        <li>
          <jump anchor="faq_not_a_valid_response">I'm getting a
          "<code>not a valid response</code> error message. What does it
          mean?</jump>
        </li>
        <li>
          <jump anchor="faq_failed_to_get_test_results">I'm getting a
          "<code>ChainedRuntimeException</code>: Failed to get the test results" 
          error message. What does it mean?</jump>
        </li>
        <li>
          <jump anchor="faq_send_multipart">How to send multipart/form-data?</jump>
        </li>
        <li>
          <jump anchor="faq_classcastexception_logfactoryimpl">I get a 
          "java.lang.ClassCastException: org.apache.commons.logging.impl.LogFactoryImpl" 
          error when I use a JUnit TestRunner different from TextTestRunner</jump>
        </li>
        <li>
          <jump anchor="faq_parametrize">How can I parametrize my Cactus tests?</jump>
        </li>
        <li>
          <jump anchor="faq_maintain_session">How do I maintain a Session between 2 Cactus test?</jump>
        </li>
        <li>
          <jump anchor="faq_eclipse_version">What version of Eclipse do I need for the 
          Eclipse plugin?</jump>
        </li>
        <li>
          <jump anchor="faq_httpclient_nosuchmethoderror">Why do I get an HttpClient 
          NoSuchMethodError when running Cactus tests with JBoss 3.x?</jump>
        </li>
        <li>
          <jump anchor="faq_load_balancing">Does Cactus work with load-balancers?</jump>
        </li>
        <li>
          <jump anchor="faq_javascript_assert">Does Cactus supports asserting HTML pages with Javascript?</jump>
        </li>
        <li>
          <jump anchor="faq_strutstestcase">I have problems using StrutsTestCase...</jump>
        </li>
        <li>
          <jump anchor="faq_https_support">Does Cactus support HTTPS?</jump>
        </li>
        <li>
          <jump anchor="faq_init_servlet">Why is my ServletContext and ServletConfig null in the servlet under test?</jump>
        </li>
      </ul>
    </section>

    <anchor id="faq_cant_find_resource"/>
    <section title="Can't find resource for cactus error message">

      <p>
        If you get the following stack trace:
      </p>

<source><![CDATA[
java.lang.ExceptionInInitializerError: java.util.MissingResourceException:
  Can't find bundle for base name cactus, locale en_GB
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:707)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:679)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:546)
]]></source>

      <p>
        it simply means that you have not put the cactus.properties file in
        your CLASSPATH (i.e. the directory which contains this file should
        be in the CLASSPATH). This file is the Cactus configuration file and
        is required. Check the Cactus
        <link href="site:howto_config">Configuration Howto</link> page for
        more information.
      </p>
    </section>

    <anchor id="faq_webxml_test_prod"/>
    <section title="How can I have a web.xml that is valid both for testing and for production?">

      <section title="Question">
        <p>
          Cactus needs to have a few entries set in the <code>web.xml</code>
          file (redirector definition and mappings mostly). The application to
          test also needs its own entries. What would be nice would be to be
          able to use the same <code>web.xml</code> file in the build process
          for both application testing and deployment to production.
        </p>
      </section>
      <section title="Solution">
        <p>
            Here's how I accomplished conditional inclusion
            of Cactus web.xml configuration.  My web.xml file is capable of
            working standalone without requiring any filtered copy to work.
            In Ant I'm doing this:
        </p>
<source><![CDATA[
<!-- Activate the Cactus web.xml configuration -->
<copy todir="${admin.build.dir}/WEB-INF"
      file="web/admin/WEB-INF/web.xml"
      overwrite="yes">
  <filterset>
    <filter token="start.cactus.config" value="--&gt;" />
    <filter token="end.cactus.config" value="&lt;!--" />
  </filterset>
</copy>]]></source>

        <p>
          In <code>web.xml</code> I have this:
        </p>

<source><![CDATA[
<!-- Cactus configuration
Note: Do not place any XML comments in this Cactus configuration section
(Ant's filtered copy is used to activate this configuration when the test
web application is built)
-->
<!-- Begin Cactus Configuration @start.cactus.config@
<servlet>
  <servlet-name>ServletRedirector</servlet-name>
  <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>
</servlet>

<servlet>
    <servlet-name>JspRedirector</servlet-name>
    <jsp-file>/somewhere/jspRedirector.jsp</jsp-file>
</servlet>

<servlet-mapping>
    <servlet-name>ServletRedirector</servlet-name>
    <url-pattern>/ServletRedirector/</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>JspRedirector</servlet-name>
    <url-pattern>/JspRedirector/</url-pattern>
</servlet-mapping>

@end.cactus.config@ End Cactus Configuration -->
]]></source>

      </section>

    </section>

    <anchor id="faq_stream_corrupted_exception"/>
    <section title="I'm getting a java.io.StreamCorruptedException error. What does it mean?">

      <note>
        This error only appears for Cactus 1.3dev (before 21/04/2002) and
        below. Cactus 1.3 no longer uses a serialized object to return test
        result. It uses an XML string.
      </note>

      <section title="Solution">
        <p>
          This exception results when client-side Cactus code attempts to talk
          to a misconfigured installation of Cactus on the server side. The
          reason for the obscure exception is this: Cactus makes two requests
          to the server. In the first, the client-side test runner requests that
          such-and-such a test be run on the server (an oversimplification,
          please see: XXXX). Immediately after the response from the server
          the client code makes a second request, this time for the results of
          the server-side test. Cactus is supposed to send back a serialized
          Object containing the results. Cactus then attempts to deserialize
          this Object from the input stream in the response. If
          Cactus is installed properly on the server, this process
          works transparently. If not (for instance the second
          request does not even arrive at a Cactus redirector) then
          the response to the second request (which very well may be
          a 404 or 500 error) will not contain the object that
          client-cactus expects. This leads to the
          StreamCorruptedException.
        </p>
        <p>
          When troubleshooting this error, the most likely prospect
          is that the requests from client-Cactus are not even
          reaching server-Cactus. This can happen when the
          <code>cactus.properties</code> contains a bad entry. For instance, I
          have run into this problem when building several different
          testing-applications. I tried to run my tests against
          <code>http://localhost/webapp1/ServletRedirector/</code> when I needed
          to be running against
          <code>http://localhost/webapp2/ServletRedirector/</code>. This can
          also happen if your web.xml file contains an error, or does not
          properly map the URLs contained in cactus.properties to the
          Cactus redirectors.
        </p>
        <p>
          A good way to check whether your requests are reaching a
          Cactus redirector is to manually enter in the URLs for all
          of the redirectors you use into the navigation bar of your
          web-browser. Actually the Cactus redirectors provide a URL just for
          that: <code>http://localhost/webapp/ServletRedirector?Cactus_Service=RUN_TEST</code>
          (this also works for the other redirectors).
        </p>
        <note>
          If you call <code>http://localhost/webapp/ServletRedirector</code>
          directly, you'll get a 500 error and get a stack trace (in the log or
          along with your error page) that says <code><![CDATA[Missing service
          name parameter [] in HTTP request.]]></code>. This is because the
          Cactus redirector expects HTTP parameter from the Cactus client side.
        </note>
        <p>
          Another likely error is that your server-side classpath
          does not contain a copy of the cactus.jar. (Cactus is
          effectively not present on the server.) According to
          e-mails on the Cactus user list, the
          <code>StreamCorruptedException</code> could also result when you are
          using the wrong version of the servlet.jar in some area
          (any version prior to 2.2, or using servlet.jar 2.2 with a
          Cactus-1.3 installation).
        </p>
      </section>

    </section>

    <anchor id="faq_chaining_requests"/>
    <section title="How can I test the chaining of several HTTP requests?">

      <section title="Question">
        <p>
          Let's imagine that I have one servlet that performs an HTTP redirect
          to a JSP page (or to another servlet). How do I test it with Cactus?
        </p>
      </section>
      <section title="Solution">
        <p>
          Short answer: you don't !
        </p>
        <p>
          Long answer: Cactus is meant to be a unit testing tool, meaning it
          lets you perform tests for a given method and then it lets you
          assert the result from that method.
        </p>
        <p>
          In the above scenario, a typical Cactus test will consist in
          verifying that the return HTTP response is an HTTP redirect (by
          checking the HTTP response code - 302 - in the <code>endXXX()</code>
          method) and possibly also checking the URL of the redirect page.
        </p>
        <p>
          Then, as a second test, you could (if you wish) verify that calling
          the URL of the JSP does return such HTML content (using HttpUnit
          integration for example). Note that this second test is rather a
          functional test than a unit test but it can still be viewed as
          unit testing the <code>doGet()</code> method of the JSP ...
        </p>
      </section>

    </section>

    <anchor id="faq_runservertests_hangs"/>
    <section title="The &lt;runservertests&gt; Ant task hangs when my server is started">

      <section title="Question">
        <p>
          When I use the <code>&lt;runservertests&gt;</code> Cactus custom Ant 
          task, it starts my server allright but then hangs and the tests are 
          not executed. What is happening?
        </p>
      </section>
      <section title="Solution">
        <p>
          It means that the <code>testURL</code> attribute you've specified
          in <code>&lt;runservertests&gt;</code> is not a valid URL. It must 
          be a URL that is valid when the server is up. To diagnosis the 
          problem simply open a browser once your server is started (i.e. when 
          the task hangs) and type the URL in your browser. An alternative to 
          debug is also to run Ant in debug mode 
          (<code>ant -debug [your target]</code>).
        </p>
        <p>
          With Cactus 1.3, the correct URL to call is the following, which is
          always valid:
          <code>http://localhost:8080/webapp/ServletRedirector?Cactus_Service=RUN_TEST</code>.
          Of course replace <code>webapp</code> by your webapp context and
          replace the port by the one you're using.
        </p>
      </section>

    </section>

    <anchor id="faq_not_a_valid_response"/>
    <section title="I'm getting a 'not a valid response' error message. What does it mean?">

      <section title="Question">
        <p>
         When I run my Cactus test, I'm getting the following:
        </p>

<source><![CDATA[
testRequestDispatcherInclude(org.apache.cactus.sample.TestSampleServlet)
  org.apache.cactus.util.ChainedRuntimeException:

Not a valid response
  at
org.apache.cactus.client.WebTestResultParser.readRootElement(
  WebTestResultParser.java;org/apache/cactus/util/log/LogAspect.java(1k):134)
]]></source>

      </section>
      <section title="Solution">
        <p>
          It means that Cactus could not connect to the server side properly.
          There could several reasons for this: a valid Redirector URL but
          not pointing to the Redirector, a secured resource, etc.
        </p>
        <p>
          To easiest way to diagnosis the problem is to enable Cactus logging
          (see the <link href="site:howto_config">Configuration Howto</link>
          for how to do this). The cactus client log
          (<code>cactus_client.log</code> will clearly give the error).
        </p>
      </section>

    </section>

    <anchor id="faq_failed_to_get_test_results"/>
    <section title="I'm getting a 'ChainedRuntimeException: Failed to get the test results' error message. What does it mean?">

      <section title="Question">
        <p>
         When I run my Cactus test, I'm getting the following:
        </p>

<source><![CDATA[
org.apache.cactus.util.ChainedRuntimeException: 
    Failed to get the test results [...]
]]></source>

      </section>
      <section title="Solution">
        <p>
         It means that Cactus failed to retrieve the test result from the 
         server side for some reason. To easiest way to diagnosis the problem 
         is to enable Cactus logging(see the 
         <link href="site:howto_config">Configuration Howto</link>
         or how to do this). The cactus client log
        (<code>cactus_client.log</code> will clearly give the error).
        </p>
      </section>

    </section>

    <anchor id="faq_send_multipart"/>
    <section title="How to send multipart/form-data?">

        <section title="Question">
          <p>
           How to send multipart/form-data to my servlet under test?
          </p>
        </section>
        <section title="Solution 1">
          <p>
            Use a recent version of Commons-httpclient, which supports 
            <link href="ext:commons_httpclient_multipart">sending multipart
            data</link>. Tobias also has a nice 
            <link href="ext:commons_httpclient_multipart_tobias">blog 
            entry</link> describing how to use Java NIO, Commons-httpclient 
            and Cactus to upload a file.            
          </p>
        </section>
        <section title="Solution 2">
          <p>
            Another solution is to use the
            <link href="ext:httpclient_other">HTTPClient</link>
            classes from Ronald Tschalar, as demonstrated in the following
            example:
          </p>

<source><![CDATA[
import HTTPClient.Codecs;
import HTTPClient.NVPair;
.
.
.
NVPair[] hdrs = new NVPair[1];

public void beginUpload(WebRequest theRequest)
{
  NVPair[] opts = { new NVPair("option", "myoption") };
  NVPair[] file = { new NVPair("comment", "/home/alan/src.zip") };
  try {
    byte[] data = Codecs.mpFormDataEncode(opts, file, hdrs);
    InputStream i = new ByteArrayInputStream(data);
    theRequest.setUserData(i);
    theRequest.setContentType(hdrs[0].getValue());
    i.close();
  } catch (IOException e) {
    System.out.println("Error Building Multipart");
  }
}
]]></source>

      </section>
    </section>

    <anchor id="faq_classcastexception_logfactoryimpl"/>
    <section title="I get a 'java.lang.ClassCastException: org.apache.commons.logging.impl.LogFactoryImpl' error when I use a JUnit TestRunner different from TextTestRunner">

        <section title="Question">
          <p>
            Cactus tests run fine when I use the JUnit TextTestRunner but 
            fails with other runners like the SwingTestRunner. I get the
            following exception:
          </p>
<source><![CDATA[
org.apache.commons.logging.LogConfigurationException:
java.lang.ClassCastException: org.apache.commons.logging.impl.LogFactoryImpl
at org.apache.commons.logging.LogFactory.newFactory(LogFactory.java:505)
at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:340)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:381) 	at
org.apache.cactus.AbstractTestCase.runBare(AbstractTestCase.java:188) 
]]></source>

        </section>
        <section title="Solution">
          <p>
	        Check the 
	        <jump href="ext:junit_faq" anchor="running_8">JUnit 
	        FAQ</jump>. Indeed, JUnit uses a special class loader to load 
	        classes that is incompatible with the Commons-Logging framework. 
	        Thus you need to put the commons-logging package in the JUnit 
	        <code>excluded.properties</code> file (see the JUnit FAQ).
		  </p>
		</section>
	</section>

    <anchor id="faq_parametrize"/>
    <section title="How can I parametrize my Cactus tests?">

      <section title="Question">
        <p>
          I would like to pass some configuration information to my
          Cactus tests but without having to hardcode them in my tests.
          Can I do this, and how?
        </p>
      </section>
      <section title="Solution">
        <p>
          The easiest solution is to pass dynamic configuration 
          information as System properties to Cactus. For example, if 
          you have to pass a username and password as HTTP parameter to
          your servletfor all your tests and you cannot control your 
          environment by defining a test user, you could write the 
          following:
        </p>
<source><![CDATA[           
public void MyTest extends ServletTestCase
{
    public void begin(WebRequest request)
    {
        request.addParameter("username", System.getProperty("username"));
        request.addParameter("password", System.getProperty("password"));
    }
    [...]
}
]]></source>
        <p>
          In order to pass the system properties to cactus you have 2 
          options:
        </p>
        <ol>
          <li>
            Pass them on the command line that you use to start the JUnit 
            Test Runner. If you're using the ServletTestRunner, then that 
            would be on the command line that you use to start your 
            container.
          </li>
          <li>
            Add these properties in the <code>cactus.properties</code> file.
            All properties found in this file are imported as System 
            Properties during the Cactus initialization.
          </li>
        </ol>           
      </section>
	</section>

    <anchor id="faq_maintain_session"/>
    <section title="How do I maintain a Session between 2 Cactus test?">

      <section title="Question">
        <p>
          I would like to use the same HTTP Session between several Cactus 
          tests. How can I do that?
        </p>
      </section>
      <section title="Solution">
        <p>
          Cactus is a unit testing framework and not a functional testing 
          framework. Each test <em>must</em> be independent of the others.
          There are several reasons for this: tests become very brittle,
          test order is not guaranteed by the JVM, etc. Thus, before each
          test you must set the fixture. This can be factorized in the
          <code>setUp()</code> method or in the Cactus <code>begin()</code>
          method.
        </p>
      </section>
	</section>

    <anchor id="faq_eclipse_version"/>
    <section title="What version of Eclipse do I need for the Eclipse plugin?">

      <p>
        The Cactus plugin for Eclipse requires Eclipse 2.1 RC2 or greater.
        It has not yet been tested with Eclipse 3.0.
      </p>      	

	</section>

    <anchor id="faq_httpclient_nosuchmethoderror"/>
    <section title="Why do I get an HttpClient NoSuchMethodError when running Cactus tests with JBoss 3.x?">

      <section title="Question">
        <p>
          When running my Cactus tests with JBoss 3.x, I get:
        </p>
<source><![CDATA[           
java.lang.NoSuchMethodError: 
  org.apache.commons.httpclient.methods.GetMethod.setRequestHeader(
  Ljava/lang/String;Ljava/lang/String;)V at [...]
]]></source>
      </section>
      <section title="Solution">
        <p>
          JBoss 3.x bundles an old version of HttpClient and Cactus requires a
          newer version. Just replace the HttpClient version in JBoss by the
          one provided by Cactus.
        </p>
      </section>
	</section>

    <anchor id="faq_load_balancing"/>
    <section title="Does Cactus work with load-balancers?">
      <p>
        Answer: No. For each test, Cactus performs 2 HTTP connections to the
        Server side: one for executing the test and one to get the test
        result. The test result is stored in the application scope
        (Servlet context). Thus, if the load-balancer directs the second
        HTTP connection to another server instance, the test result will
        not be correct.
      </p>
    </section>

    <anchor id="faq_javascript_assert"/>
    <section title="Does Cactus supports asserting HTML pages with Javascript?">
      <p>
        Cactus provides powerful response assertion through its integration 
        with HttpUnit. HttpUnit does support asserting page containing 
        Javascript. However, the Cactus integration with HttpUnit currently 
        does not support this use case (There's a 
        <a href="http://issues.apache.org/jira/secure/ViewIssue.jspa?key=CACTUS-76">bug</a> 
        opened for adding this support).
      </p>
    </section>

    <anchor id="faq_strutstestcase"/>
    <section title="I have problems using StrutsTestCase...">
      <p>
        <a href="ext:strutstestcase">StrutsTestCase</a> is a project separate 
        from Cactus. It has its own mailing list/forum. Please post your 
        questions there.
      </p>
    </section>

    <anchor id="faq_https_support"/>
    <section title="Does Cactus support HTTPS?">
      <p>
        No, Cactus doesn't support HTTPS. The reason is that we don't think 
        it's necessary. Whether you use HTTP or HTTPS should be transparent 
        to the tested code. And you should run the tests in a test 
        environment anyway, which doesn't necessarily need to be HTTPS just 
        because the production environment is. Of course, if you have good 
        arguments for HTTPS support and a patch, we might change our 
        collective mind :-)
      </p>
    </section>

    <anchor id="faq_init_servlet"/>
    <section title="Why is my ServletContext and ServletConfig null in the servlet under test?">
      <p>
        You must initialize the servlet with the implicit cactus config 
        object (see the 
        <link href="site:howto_testcase_servlet">ServletTestCase
        principles</link> documentation for more details). For example:
      </p>
<source><![CDATA[           
MyServlet servlet = new MyServlet();
servlet.init(config);
]]></source>
    </section>

  </body>
</document>
