Monday, June 29, 2009

Keep your documentation website backwards compatible

Most engineers know that you should at least try to keep your software and hardware backward compatible.
If it is not excessively expensive, the new version of your program should read data files created with previous versions, your newest 10Gbit switch should talk to the 100Mbit legacy one etc.

People seem to forget that this should also apply to your website with product documentation.

I have a nice Cerberus Pentagram P6381-0 wireless router that usually works perfectly. Today, however, I had a power glitch that left the router in unusable state.
I managed to get to the vendor's site with documentation, but the closest model I could get the PDF for was P6381-2 (can you spot the difference? ;-))
I managed to reset the router to factory settings using that doco - but surprise, surprise: the default password does not work.

Almost an hour later I googled for the exact model number and I found the right manual on the very same site - it just was not linked in the support links section. If it was, it would have spared me 2 hours of looking for the problem.

And yes, the default passwords are different for P6381-0 and P6381-2 models.

Lesson learned: keep the documentation for older releases easily findable for as long as you have people using it.
This applies esp to products that are not likely to be upgraded as soon as you release the new version: either because it is a piece of hardware or when upgrade costs money or significant effort.

Thursday, June 4, 2009

Unit testing your Intellij Idea plugin in a CI build

It's relatively easy to write a unit test for your Intellij Idea plugins that would work from under Idea.
Just extend an IdeaTestCase or LightIdeaTestCase, add some Mockito and enjoy :-)

The challenge is to set this up for an Ant build run on a continuous integration server like Bamboo - you just don't get the Idea set up on every potential elastic build agent that may turn out to run your build ;-)
I wanted my build to be self-contained - no external dependencies on stuff that may or may not be there, everything gets nicely checked out from the svn.

I came up with the following configuration:

Set up new Idea home



My lib contains an idea_version folder reflecting the structure of the actual Idea installation:

  • lib folder containing all the jars from Idea's lib dir - definitely all are not required, but it seemed to be too much work to actually find out which ones are,
  • bin folder that is necessary for the test framework to start - namely it should contain:

    • idea.properties - just copied as is, this is the marker that Idea uses to determine the folder is it's home,
    • log4j.dtd - also copied as is,
    • log.xml - modified so that the 'headless' Idea can find the log4j.dtd file:
      <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

      You may use an unmodified one, but then you need to make sure that the log4j.dtd file is in the current working directory of the test runner.


Set up test runner



I use this test target:
<property name="idea.home" location="${basedir}/lib/idea_9833"/>

<target name="idea7.test" depends="idea7.test.build, idea7.testproject">
<mkdir dir="${output}/test/xml-report"/>
<mkdir dir="${output}/test/system/log"/>
<junit dir="${output}/test" fork="true" forkmode="once" printsummary="on">
<jvmarg line="${jvm.args}"/>
<jvmarg value="-Xbootclasspath/a:${idea.home}/lib/boot.jar"/>
<jvmarg value="-Xmx256M"/>
<jvmarg value="-ea"/>
<jvmarg value="-Xdebug"/>
<!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006"/>-->
<sysproperty key="java.awt.headless" value="true"/>
<sysproperty key="java.compiler" value="NONE"/>
<sysproperty key="idea.config.path" value="${output}/test/config"/>
<sysproperty key="idea.system.path" value="${output}/test/system"/>
<sysproperty key="idea.load.plugins" value="false"/>
<classpath>
<path path="${java.class.path}"/>
<path refid="testpath"/>
<fileset dir="${idea.home}/lib" includes="*.jar"/>
<pathelement path="${output}/test/classes"/>
<pathelement path="${idea.home}/bin"/>
</classpath>
<batchtest todir="${output}/test/xml-report">
<fileset dir="${basedir}/test" includes="${test.includes}"
excludes="${test.excludes}"/>
<formatter type="xml"/>
<formatter type="plain"/>
</batchtest>
</junit>
</target>


Some highlights:
  • Make sure both Idea lib and bin are on the classpath.
  • Make sure you have Java on the classpath - for some reason I had not.
  • Notice the -Xbootclasspath jvmarg - <bootclasspath> hasn't worked for me.
  • Remote debugger may be handy sometimes.