Thursday 7 July 2011

Using System.getProperty() with Jenkins builds

One of my recent projects needed to be able to manipulate file paths according to a set of rules and read and process files directly from the file system. When it came to writing unit tests for this module, I was faced with a dilemma. My usual approach for this kind of system is to use the "Test Double" pattern to hide environment specific details from the tests to make them portable across different platforms and different developer environments. However, the module was about 80% file processing code - which made that approach impractical. So I ended up with a suite of tests that required absolute file paths to work properly.

At this point I should mention how it's near impossible to obtain an absolute file path in Java - specially if you are trying to be portable as possible. All my test data was in the src/test/resources/testjobs directory of the project. The absolute path to this was: /home/charithe/workspace/mercury/src/test/resources/testjobs. Obviously, when somebody else checks out this code, the first part of this path would be something else entirely. I played around quite a bit with ClassLoader.getResource et al, but had no luck whatsoever in making the path portable. In desperation, I even tried accessing Maven properties like project.source.directory - which didn't work out as is to be expected.

With time running out, I did the quickest hack imaginable. I added a custom JVM property named testdata.path to the run configuration and the test suite was changed to call System.getProperty("testdata.path") to retrieve the first half of the path, which was then prepended to the unchanging portion of the path to get the full absolute path. This worked out quite well. I could run the tests successfully from within Eclipse by adding the property definition to the run configuration and ditto for maven with the command:
mvn test -Dtestdata.path=/home/charithe/workspace/mercury

It was a short reprieve though. Once my code was checked-in, the Jenkins build failed miserably. My custom property was resolving to null even though I had added it explicitly to the maven command line of the Jenkins job configuration. After doing a quick Google search, it turns out that this is a known bug/feature of Jenkins (http://jenkins.361315.n4.nabble.com/System-properties-hidden-by-hudson-while-test-execution-td380285.html)

The fix was quite simple. In fact, it was so simple, when I found it out, I had to bang my head against the desk for not figuring that out earlier. The Maven sure-fire plugin has the ability to pass properties to the unit tests. This can be done through the plugin configuration section of the pom. (http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html). The relevant section of my pom.xml looks as follows:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<systemPropertyVariables>
<testdata.path>${basedir}/src/test/resources</testdata.path>
</systemPropertyVariables>
</configuration>
</plugin>