Archive

Posts Tagged ‘ant’

Filtering FindBugs reports by rank.

May 2, 2012 2 comments

I’ve been messing with the FindBugs Ant task today to incorporate it into my company’s automated build for a JEE application. One task I wanted to do was filter the bug report by rank. There is an easy way to do this, which is documented here. However, the documentation is not clear on exactly how FindBugs uses the rank value. After some experimentation, I was able to deduce that the value in the rank tag is used differently depending on whether the XML filter file is specified as an “includeFilter” or “excludeFilter” in the FindBugs Ant task. When specifying rank in an “includeFilter”, the FindBugs report is filtered to contain only bugs with the rank value and above. When specifying rank in an “excludeFilter”, the  report is filtered to contain only bugs below the given rank.

So, for example, if you want only bugs of ranks 10 to 20 to show in your report you must include the attribute “includeFilter” in your findbugs task

...
includeFilter="./findbugsFilter.xml"
...

Your findbugsFilter.xml would need to include a single reference to the Rank tag like this

<Match>
  <Rank value="10"/>
</Match>

On the other hand, if you want to see only bugs with ranks 1, 2 and 3, you must specify your filter as an “excludeFilter”

...
excludeFilter="./findbugsFilter.xml"
...

Your match tag should look like this

<Match>
  <Rank value="4"/>
</Match>

FindBugs appears to only use one  instance of the Rank tag.

I tried several ways to produce a filtered range of bugs in different, but useful ways such as ranks 4 – 9. However, there just doesn’t seem to be a logical way to do this. If you specify the Rank tag more than once or in an “includeFilter” and “excludeFilter” you get unexpected results. It appears that you can only rely on one Rank tag in one filter file.

I perused the code for the FindBugs Ant task for version 2.0.1 rc1 and did find an undocumented (at least not here) attribute “maxRank”. The comment from the source code defines this attribute to mean “maximum rank issue to be reported”. You can use it like this:

<findbugs home="${env.FINDBUGS.HOME}"
                     output="xml:withMessages"
                     outputFile="${findbugs.report.dir}/findbugs.xml" 
                     reportLevel="medium"
                     maxRank="9"
                     debug="false">
...
</findbugs>

Defining that attribute will effectively filter the bugs so that only bugs with ranks 1 through 9 visible in the generated report.

 

I thought this part of the Ant task was particularly confusing and not documented sufficiently, even though it’s quite a useful feature. If I’ve made any mistakes in my assessment of filtering by bug rank, please leave a comment with a correction.

Categories: Software Engineering Tags: , ,

Getting Jython Modules to Work with the WebSphere wsadmin Tool.

December 14, 2010 Leave a comment

I just finished wrestling with a problem for a day and a half – I’m writing down the solution for your benefit.  I’m not going into excruciating detail because I don’t understand it all.  This is just a quick look at the problem and what worked for me.  I hope it saves a little bit of time for a few people.

The Context

I am working on a set of scripts that I will use to automatically deploy a JEE EAR file to an IBM WebSphere version 7.0 (WAS 7) application server.  Even so, I believe this blog applies equally well to deploying a WAR file and on version 6.1 – 7.0 of WAS.  I am using a combination of Windows batch scripts, Ant scripts and Jython scripts.  The Jython scripts are being run through the wsadmin tool to do the WAS admin work.  I am setting the deployment scripts up in both a test and production environment.  The test environment is deploying from an automated build, which uses Ant to start the deployment process.  The production environment does not use Ant.  In both environments, there is a batch script that passes a Jython script to the wsadmin tool, where the Jython script does the actual WAS admin work (e.g. starting/stopping servers, deploying code and saving the configuration).

So to summarize, there are two deployment scenarios:

  1. An Ant script, via the exec task, calls a Windows batch script, which runs the wsadmin tool with the necessary parameters, one of those parameters being a Jython script that does the deployment work.
  2. A Windows batch script (which is part of another automated scheduling system) calls another Windows batch script, which runs the wsadmin tool with the necessary parameters, one of those parameters being a Jython script that does the deployment work.

The Problem

Once you’ve gotten jaded enough on IBM products and other such “enterprise-level tools”, the above setup is “basic”, so I’m assuming you’re just as twisted as I am and am not going to explain it further.  My actual problem is that I have written a Jython module that I want to use in my Jython deployment scripts.  Python, and thus Jython, is just like Java in that it has a specific route it follows when searching for referenced modules.  In regular Python programs the environment variable that is analogous to Java’s CLASSPATH is called PYTHONPATH.  The idea is exactly the same in both languages, the Python runtime has to know about all the directories where you expect Python modules to be in order for it to find them.  The same is true for Jython, although you have to setup the path a little differently since you’re running on the JVM.

All this isn’t complicated, but the wsadmin tool does make it harder to deal with.  The wsadmin tool sets up a very particular environment for itself, which is what tripped me up for so long.  Not to mention the muddled mess of running Python, via Jython, via the wsadmin tool, via a batch script, via an Ant script.  I was having a lot of trouble in actually importing my module because I did not have the Python path setup correctly, even though all of my Jython files were in the same directory.  If you have a Python file in the same directory as another module you are importing, you don’t have to do any special setup for Python to resolve the import.  However, with Jython and the wsadmin tool, your Jython files are being run out of the directory where either the JVM or wsadmin tool are being executed from, respectively.  This means that you have to setup the Python path, even if all of your Jython files are in the same directory.

The Solution(s)

It turns out that this is easy to solve, you just have to setup the Python path.  That seems obvious now, but since Python seems to handle module resolution fine in the same situation, it was confusing that Jython doesn’t.  An alternate solution is to be explicit about where the wsadmin tool should execute.  I ended up using each solution, one for the test environment and one for production.  In the test environment, where I’m starting with an Ant script, I’m using the dir attribute of the exec command to specify where to execute the command from.  This keeps the working directory for the wsadmin tool in the same place where my Jython scripts reside and allows the Jython runtime to find my referenced modules.  By “working directory” I mean the directory from which the wsadmin tool is actually executed. Without the dir attribute specified, the wsadmin tool will run in a different directory (the directory where the wsadmin.bat file is installed, I believe) and my Jython files will not be on the Python path.  Here’s an example of the Ant task:

<!-- The dir attribute is VERY IMPORTANT and allows the Jython scripts to import other scripts from this directory.-->
<exec executable="${env.WORKSPACE}/wasscripts/DeployWebServiceToCluster.bat"
      failonerror="true"
      failifexecutionfails="true"
      dir="${env.WORKSPACE}/wasscripts"
>
  <env key="WSADMIN_HOME" value="${env.WSADMIN.7.HOME}"/>
  <arg value="${wsadmin.props.file}"/>
  <arg value="${env.WORKSPACE}/wasscripts"/>
  <arg value="${env.WORKSPACE}/dist/${ear.file.name}"/>
  <arg value="${was.dmgr.name}" />
  <arg value="${was.cell.name}" />
  <arg value="${was.cluster.name}" />
  <arg value="${ant.project.name}"/>
  <arg value="${was.user}"/>
  <arg value="${was.user.password}"/>
</exec>

For the production environment I took the simpler route of passing in the Python path to the script that starts the wsadmin tool.  The wsadmin tool allows you to do this with the command line parameter -javaoption.  Here’s an example of what I did in the Windows batch script:

@rem %1 - Absolute path to the properties file.
@rem %2 - User with admin access to the WAS deployment manager.
@rem %3 - Password for the admin user.
@rem %4 - Absolute path to the Jython scripts folder.
@rem %5 through %8 - Parameters passed to Deploy_To_Production.py (see file for details).

call "%WSADMIN_HOME%\wsadmin.bat" -p %1 -user %2 -password %3 -javaoption "-Dpython.path=%~4" -f %4/deploy/Deploy_To_Production.py %5 %6 %7 %8
set ERRORLEVEL=%MYERRORLEVEL%
exit /B %MYERRORLEVEL%

The most crucial part is the -javaoption “-Dpython.path=%~4″.  Notice first that the entire value of the -javaoption parameter is enclosed in quotes.  It seems that you have to do this to get it to work correctly when passed to the JVM that gets started to run your Jython script. Since the entire value for the -javaoption parameter is in quotes, I’m using the Windows batch script trick (%~4 as opposed to just %4) to remove quotes from the fourth parameter to the batch script.  As an example, if the path passed into the batch script above as parameter four is

C:\temp

%4 will produce

"C:\temp"

whereas %~4 will output

C:\temp

This is also necessary to get things to work correctly.

Conclusion

I realize that there are many holes in my explanation.  The point is to briefly convey how to solve this problem if you should get hung up on it too.  I’m continuing to learn more about how to use Jython with the wsadmin tool for WAS scripting, so feel free to ask for clarification or about related problems.  Helping you will give me a chance to learn more as well.  Also, I found a pretty good blog about wsadmin scripting while I was researching this problem.

Some Thoughts on Integrating SoapUI Functional Tests with Your Build

June 23, 2010 6 comments

The development team I’m a part of at Ohio Mutual Insurance Group is about to develop our own web services for the first time and I want to make sure we test them properly. So, for about two months now I have been experimenting with using SoapUI to aid in developing our services.  One very important aspect of my experiment is to determine how difficult it is to run SoapUI functional tests from a Hudson CI job. In this blog are my rough thoughts on how well SoapUI functional tests integrate with the build process we use on Hudson.

Functional testing is not all SoapUI does, but it is one outstanding feature that I’m focusing on for now. Even though SoapUI has a solid interface for running functional tests, it doesn’t make any sense to have compilation, unit tests, and deployment automated but not functional tests.  It appears that the SoapUI developers feel the same way and have provided some help in this area. There are two ways to run SoapUI functional tests automatically: integrate with JUnit or use the SoapUI “testrunner” shell script.   Unfortunately, the official documentation on both is sparse (see the hyperlinks in the previous sentence)  and not helpful beyond a bare minimum of support.

Note: All mention of SoapUI in this entry is related to version 3.5.1.

Integrating with JUnit

The documentation for how to integrate with JUnit is awful.  It barely provides the necessary information for using JUnit and only offers part of the story.  If you really want to know how to run your SoapUI tests from JUnit you’re mostly stuck with using the SoapUI JavaDocs and your own experimentation (Intellisense is your friend here).  However, the one advantage that this approach has over using the testrunner script is that you can have more control over how and when tests are executed. If you need that control but want to automate the process of running the test cases, this is the way to do it. But, if you just need to automate the test case runs without control, the command line test runner is preferable. Here is some help with the JUnit method.

To run SoapUI tests from JUnit tests you have to use the SoapUI API.  This means that the SoapUI libraries need to be in your Classpath.  The main archive needed is the bin\soapui-3.5.1.jar file.  If they’re not already in your Classpath, you may also need some of the JARs in the lib directory.  At a minimum you will need the xmlpublic-2.4.0.jar because it contains the XMLException class that is thrown by some of the classes in the SoapUI API.

When you’ve got your Classpath setup you can use the SoapUI API in your JUnit tests.  There are several ways to run SoapUI functional tests with the SoapUI API.  You can just run all the test cases in all the test suites in a SoapUI project without control over the order (you choose whether to run them synchronously or asynchronously), run a whole test suite, or run individual test cases within a test suite.  For the second and third options, you can either blindly iterate over test suites and test cases or you can run test suites or test cases by name.  Which way you run the tests is based on how much control you need over the order of test execution.  When running a test suite you have control over whether the test cases in the suite are run synchronously or asynchronously.  The options that you have available reflect what you can do in SoapUI’s user interface.  The problem is digging through the JavaDocs to find out which methods on what objects to call.

Here is an example of a JUnit test that runs all the test cases in a SoapUI project in two different ways.  The lessControl method just runs every test case in the project in the simplest way whereas the fullControl method iterates over the test suites and the test cases in the project.

package com.omig.soapUISamples;

import java.util.List;
import org.junit.Test;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.model.support.PropertiesMap;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.model.testsuite.TestRunner;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.model.testsuite.TestRunner.Status;
import com.eviware.soapui.tools.SoapUITestCaseRunner;
import static org.junit.Assert.*;

public class SoapUITest {

@Test
public void lessControl() throws Exception {
SoapUITestCaseRunner runner = new SoapUITestCaseRunner();
runner.setProjectFile(“SoapUIWorkspace/Sample-soapui-project.xml”);
runner.setPrintReport(true);  //Outputs a small table to stdout of test results.
runner.run();
}

@Test
public void fullControl() throws Exception {
WsdlProject project = new WsdlProject(“SoapUIWorkspace/Sample-soapui-project.xml”);
List<TestSuite> testSuites = project.getTestSuiteList();
for( TestSuite suite : testSuites ) {
List<TestCase> testCases = suite.getTestCaseList();
for( TestCase testCase : testCases ) {
System.out.println(“Running SoapUI test [" + testCase.getName() + "]“);
TestRunner runner2 = testCase.run(new PropertiesMap(), false);
assertEquals(Status.FINISHED, runner2.getStatus());
}
}
}
}

With the code above you’ve got a hint at how run SoapUI functional tests from a JUnit test.  To actually make this automatic you’ve got (at least) one more step.  In my situation we use Ant to script our software builds.  We then use Hudson to schedule the builds and make it all run automatically.  There are a lot of other ways you could do this but I’ll only show the Ant way here.  Any build tool that has support for JUnit will suffice.

Below is an example of an Ant task that runs the JUnit tests that are executing the SoapUI tests.  The JUnit output is being generated in XML format and sent to a folder named soapui-test-reports.

<path id="classpath">
    <!-- The path to the lib folder in the SoapUI installation.-->
    <fileset dir="${env.SOAPUI.LIB}"/>
    <!-- The path to the bin folder in the SoapUI installation.-->
    <fileset dir="${env.SOAPUI.BIN}"/>
</path>

<path id="soapui-workspace">
    <fileset dir="SoapUIWorkspace">
      <include name="**/*.xml"/>
    </fileset>
</path>

<target name="soapui-tests" depends="compile">
    <mkdir dir="../soapui-test-reports" />
    <junit printsummary="withOutAndErr"
           showoutput="true"
           haltonerror="on"
           haltonfailure="on"
           filtertrace="off"
           fork="no"
           forkmode="once">
      <classpath refid="classpath" />
      <classpath refid="soapui-workspace" />
      <formatter type="xml" />
      <batchtest todir="../soapui-test-reports">
        <fileset dir="tests">
                <include name="**/*SoapUI*.java"/>
        </fileset>
      </batchtest>
    </junit>
</target>

Testrunner Script

The documentation for the testrunner script is much clearer than for integrating with JUnit.  Integrating the testrunner.bat file with your build process is simple and straight-forward. An example of an Ant task to do this is shown below.  See SoapUI’s documentation for an explanation of the command line switches.

<target name="soapui-tests-cmdline" depends="compile">
        <exec executable="${env.SOAPUI.BIN}/testrunner.bat"
                  failonerror="yes"
                  failifexecutionfails="yes">
                <arg value="-rjaf"/>
                <arg path="../soapui-test-reports"/>
                <arg path="SoapUIWorkspace/Insured-Access-soapui-project.xml"/>
        </exec>
</target>

Which Method Is Best?

In my experience so far the command line testrunner tool is the better method for several reasons:

  1. There’s less work because you do not have to write a JUnit test suite/case to run the SoapUI tests.
  2. It creates a less fragile environment because writing a JUnit test to run the SoapUI tests makes it very difficult not to hard code the path to the SoapUI project file. You don’t have to worry about this with the command line because the input to script is parametrized.
  3. The command line test runner can output “correct” JUnit output. The JUnit reports generated by the command line test runner split results by test suite then test case. This is ideal when the results are viewed graphically because you get a full count of actual test cases run and you can drill-down to the individual test cases to see its run status*.
  4. To integrate with JUnit you have to use the SoapUI API, which is not documented well. There are Javadocs, but actual documentation is sparse in them.

* As far as I can tell it is difficult or impossible to do this by integrating with JUnit manually. To do so you would have to somehow generate one JUnit test for each test case in all the test suites. The SoapUI API allows you to easily iterate over the test suites and test cases, but there is no way in Java to dynamically generate methods for each test case.

Follow

Get every new post delivered to your Inbox.

Join 126 other followers