9 Replies Latest reply on Jul 10, 2008 12:04 AM by kragoth

    JSFUnit/Ant/Cargo

      So my goal is to use Ant to automate the execution of a suite of JSFUnit tests. I have an Ant script that currently does the following:

      - Builds the standard war
      - Uses the jsfunitwar Ant task to "JSFUnify" the war (edits web.xml and copies all required jars to WEB-INF/lib)
      - Uses cargo to deploy the JSFUnit-ready war to JBoss and starts the application server.

      All goes well, though I'm left wondering how I can kick off the test suite from Ant. Has anyone done this yet or able to offer any guidance?

      Thanks.

      justin

        • 1. Re: JSFUnit/Ant/Cargo
          ssilvert

          Kragoth is our Ant/JSFUnit expert, but I think he's out for a week or two.

          Basically, you just run your JUnit tests like you would any other. Cactus takes care of redirecting the actual test to your running container. That's why your test needs to extend the Cactus ServletTestCase. See http://jakarta.apache.org/cactus/integration/manual/howto_config.html for all the details of how this works.

          There is also this page for running Cactus tests with ant which might be useful: http://jakarta.apache.org/cactus/integration/ant/index.html

          Stan

          • 2. Re: JSFUnit/Ant/Cargo
            kragoth

            I'm back from holidays! :)

            I didn't realise I was the Ant/JSFUnit expert lol! But all our JSFUnit tests are run through ant so our continuous build environment can run the tests as well.

            I'm going to attach some of our ant targets here so you can see how we do it.
            Note: This is probably not the most efficient or clean way of doing it, but I just havn't got around to cleaning it up.

            Seeings you have already got the jsfunitwar target working I'm going to basically ignore that part.

            So, once the app is deployed to your server this is what I do.

            <target name="run.full.suite" depends="init">
             <mkdir dir="${junit.xml.dir}"/>
            
             <gekko.junit>
             <classpath>
             <fileset dir="${lib.dir}/jsf-unit">
             <include name="**/*.jar"/>
             </fileset>
             <fileset dir="${gekko-shared.lib.test.dir}">
             <include name="junit/*.jar"/>
             </fileset>
             <fileset dir="${gekko-shared.lib.prod.dir}">
             <include name="**/*.jar"/>
             </fileset>
             <fileset dir="${gekko-services.lib.dir}">
             <include name="**/*.jar"/>
             </fileset>
            
             <pathelement location="${classes.test}"/>
             <pathelement location="${classes.prod}"/>
             </classpath>
            
             <jvmarg
             value="-Dcactus.contextURL=http://${tomcat.hostname}:${tomcat.port}/${tomcat.gekko.webapp}"/>
            
             <formatter type="xml" usefile="yes"/>
            
             <test name="gekko.web.jsfunit.GekkoWebJSFFullSuite"
             todir="${junit.xml.dir}" outfile="${junit.report.file}"/>
             </gekko.junit>
            
             <junitreport todir="${junit.xml.dir}" tofile="${junit.report.file}">
             <fileset dir="${junit.xml.dir}">
             <include name="*.xml"/>
             </fileset>
             <report todir="${junit.xml.dir}"
             styledir="${lib.dir}/jsf-unit"
             format="noframes"/>
             </junitreport>
             </target>
            

            Note the lines:
            <test name="gekko.web.jsfunit.GekkoWebJSFFullSuite"
             todir="${junit.xml.dir}" outfile="${junit.report.file}"/>
            

            obviously here is where you set the path to your test suite. (We put all our tests into a suite to make it easier...I will assume you do this)


            Our gekko.junit macro is defined as:
            <presetdef name="gekko.junit">
             <junit
             showoutput="yes"
             fork="yes"
             printsummary="yes"
             haltonfailure="yes"
             haltonerror="yes">
            
             <jvmarg value="-Dlog4j.output.dir=${log.output.dir}"/>
             <jvmarg value="-Dlog4j.configuration=file:///${gekko.services.test.suite.log.file}"/>
             <jvmarg value="-Denv.override.dir=${env.override.dir}"/>
            
             <!-- without the usefile setting, you don't see a
             stack trace on the console -->
             <formatter type="brief" usefile="no"/>
            
             </junit>
             </presetdef>
            

            Nothing fancy there. Just sets up a bunch of environment variables.

            Hope this helps. If you need any more explanation just let me know.
            Maybe I should write a wiki page on this :P

            • 3. Re: JSFUnit/Ant/Cargo
              ssilvert

               

              "Kragoth" wrote:
              Maybe I should write a wiki page on this :P

              Please do. What we have now is rather poor. Feel free to rewrite it:
              http://wiki.jboss.org/wiki/JSFUnitWithAnt

              Stan

              • 4. Re: JSFUnit/Ant/Cargo

                Thanks, guys. I will give this a go.

                Justin.

                • 5. Re: JSFUnit/Ant/Cargo

                  Kragoth, thanks again, it works well.

                  A couple things I ran into:

                  For some reason, the junit task generates two almost identical xml report files: ${junit.report.file} and ${junit.report.file}.xml (substitute whatever you set that property to). There are some whitespace differences in the files and one or two minor xml differences (e.g., the testsuite tag includes an "id" attribute in one and not the other). Not sure if I'm doing something strange. Do you see this? It's more of an annoyance than anything else (the test suite only runs once).

                  There appears to be memory leak issues in htmlunit (js threads not being cleaned up after tests run?) that requires me to use a very large max jvm mem size (our suite of ~110 tests bloats the jvm to over 1.2gigs that never gets cleaned up). Unfortunately, I was unable to do this in Cargo 0.9 due to http://jira.codehaus.org/browse/CARGO-557. I'm currently working on getting this running with a cargo svn build. Just something to keep in mind.

                  Justin.

                  • 6. Re: JSFUnit/Ant/Cargo

                    In case anyone is interested, here is what I ended up doing to automate testing...

                    I have an init ant target that defines properties, classpath, macros, etc:

                     <target name="init">
                    
                     <echo message="Defining properties, classpath, and macros"/>
                    
                     ... project specific stuff...
                    
                     <!-- Define jsfunitwar Task -->
                     <taskdef name="jsfunitwar"
                     classname="org.jboss.jsfunit.ant.JSFUnitWarTask"
                     classpathref="compile.classpath"/>
                    
                     <!-- Register Cargo Ant Tasks -->
                     <taskdef resource="cargo.tasks"
                     classpathref="compile.classpath"/>
                    
                     <!-- Define my-junit -->
                     <presetdef name="my-junit">
                     <junit showoutput="yes" fork="yes" printsummary="yes"
                     haltonfailure="no" haltonerror="no">
                     <classpath>
                     <fileset dir="${libDir}">
                     <include name="*.jar" />
                     </fileset>
                     <pathelement location="${classDir}" />
                     </classpath>
                     <jvmarg value="-Dlog4j.output.dir=${logDir}" />
                     <jvmarg value="-Dcactus.contextURL=http://${jboss-hostname}:${jboss-port}/${jsfunitAppName}" />
                     </junit>
                     </presetdef>
                    
                     <!-- Macro to start JBoss -->
                     <macrodef name="jboss-start">
                     <sequential>
                     <fail unless="env.JBOSS_HOME"
                     message="JBOSS_HOME environment variable must be set"/>
                     <echo message="Starting Cargo/JBoss..."/>
                     <echo message="Using JBOSS_HOME = ${env.JBOSS_HOME}"/>
                     <echo message="Using war = ${jsfunitAppName}.war"/>
                    
                     <cargo containerId="jboss4x" home="${env.JBOSS_HOME}"
                     output="${logDir}/jboss-server.log" log="${logDir}/cargo.log"
                     action="start" wait="false">
                     <configuration type="existing" home="${env.JBOSS_HOME}/server/${jboss-config}">
                     <property name="cargo.jboss.configuration" value="${jboss-config}"/>
                     <property name="cargo.servlet.port" value="${jboss-port}"/>
                     <property name="cargo.logging" value="${jboss-logging}"/>
                     <property name="cargo.rmi.port" value="${jboss-rmi-port}"/>
                     <property name="cargo.jvmargs" value="-Xmx2048m -Xms128m"/>
                     <deployable type="war" file="${distDir}/${jsfunitAppName}.war"/>
                     </configuration>
                     </cargo>
                     </sequential>
                     </macrodef>
                    
                     <!-- Macro to stop JBoss -->
                     <macrodef name="jboss-stop">
                     <sequential>
                     <fail unless="env.JBOSS_HOME"
                     message="JBOSS_HOME environment variable must be set"/>
                     <echo message="Stoping Cargo/JBoss..."/>
                     <cargo containerId="jboss4x" home="${env.JBOSS_HOME}" action="stop">
                     <configuration type="existing" home="${env.JBOSS_HOME}/server/${jboss-config}">
                     <property name="cargo.jboss.configuration" value="${jboss-config}"/>
                     <property name="cargo.servlet.port" value="${jboss-port}"/>
                     <property name="cargo.logging" value="${jboss-logging}"/>
                     <property name="cargo.rmi.port" value="${jboss-rmi-port}"/>
                     <property name="cargo.jvmargs" value="-Xmx2048m -Xms128m"/>
                     </configuration>
                     </cargo>
                     </sequential>
                     </macrodef>
                    
                     </target>
                    


                    Here is the jsfunit target that "JSFUnifies" the war:
                     <target name="jsfunit" depends="prepare,init,compile,compile-jsfunit,war">
                     <jsfunitwar srcfile="${distDir}/${appName}.war"
                     destfile="${distDir}/${jsfunitAppName}.war"
                     autoAddJars="false">
                     <lib dir="${jsfunitlibDir}">
                     <include name="*.jar"/>
                     </lib>
                     <TestRunner/>
                     </jsfunitwar>
                     </target>
                    


                    Here is the target that deploys the jsfunit war and starts JBoss, runs the test suite, stops JBoss, and undeploys the war:
                     <target name="run-tests" depends="jsfunit,undeploy">
                     <fail unless="env.JBOSS_HOME"
                     message="JBOSS_HOME environment variable must be set"/>
                     <jboss-start/>
                     <my-junit>
                     <test name="net.mycompany.MyTestSuite"
                     todir="${logDir}" outfile="${junitReportFile}">
                     <formatter type="xml" usefile="yes"/>
                     </test>
                     </my-junit>
                     <junitreport todir="${logDir}" tofile="${junitReportFile}">
                     <fileset dir="${logDir}">
                     <include name="${junitReportFile}.xml"/>
                     </fileset>
                     <report todir="${logDir}" format="noframes"/>
                     </junitreport>
                     <jboss-stop/>
                     <delete file="${deployDir}/${jsfunitAppName}.war"/>
                     </target>
                    


                    justin

                    • 7. Re: JSFUnit/Ant/Cargo
                      kragoth

                      Ok, I havn't had any issues with memory leaks. That being said I havn't really been looking at my memory profile that much. However, I'm booting the jvm with just default args. or maybe 256MB of heap space. Nothing like 1GB thats for sure!

                      So, I'm wondering, is there a specific test that causes the memory leak or do you experience the same sort of behaviour on all tests?

                      And out of curiosity how many tests are you running. I'm currently only running around 6 or so large tests that test core functionality of our system.

                      • 8. Re: JSFUnit/Ant/Cargo

                        'jinpsu' and I are working on the same project. Apparently there is an issue with a4j:poll and HtmlUnit such that it leaves javascript threads running indefinitely (thus gobbling up memory). We have quite a few pages with a4j:poll controls. It doesn't prevent our tests from running, but it does require a TON of memory to get through them.

                        Here is the HtmlUnit open issue:
                        http://sourceforge.net/tracker/index.php?func=detail&aid=2014629&group_id=47038&atid=448266

                        Brian

                        • 9. Re: JSFUnit/Ant/Cargo
                          kragoth

                          Well, that would explain why I havn't experienced any problems. I'm not using much ajax stuff at the moment. At least I'll know what the problem is when I run into it later on when I start doing more ajax stuff.