Using Hudson for C++/CMake/CppUnit

Update: Hudson for C++/CMake/CppUnit Revised

As a follow-up to Using grails projects in Hudson, here is another not-so-standard usage of Hudson: C++ projects with CMake and CppUnit. Let’s see how that works out.

As long as you have Java/Ant/JUnit based projects, a fine tool that it is, configuration of Hudson is pretty straight forward. But if you have a C++ project with CMake as build system and CppUnit for your unit testing, you have to dig a little deeper. Fortunately, Hudson provides the possibility to execute arbitrary shell commands. So in order to build the project and execute the tests, we can simply put a shell script to work:

   # define build and installation directories
   BUILD_DIR=$WORKSPACE/build_dir
   INSTALL_DIR=$WORKSPACE/install_dir

   # we want to have a clean build
   rm -Rf $BUILD_DIR
   mkdir $BUILD_DIR
   cd $BUILD_DIR

   # initializing the build system
   cmake  ..  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR

   # fire-up the compiler
   make install

Environment variable WORKSPACE is defined by Hudson. Other useful variables are e.g. BUILD_NUMBER, BUILD_TAG and CVS_BRANCH.

But what about those unit tests? Hudson understands JUnit test result files out-of-the-box. So all we have to do is make CppUnit spit out an xml report and then translate it to JUnit form. To help us with that, we need a little xslt transformation. But first, let’s see how we can make CppUnit generate xml results (a little simplified):

#include <cppunit/necessary/CppUnitIncludes/>
...

using namespace std;
using namespace CppUnit;

int main(int argc, char** argv)
{
   TestResult    controller;
   TestResultCollector result;
   controller.addListener(&result);

   CppUnit::TextUi::TestRunner runner;
   runner.addTest( TestFactoryRegistry::getRegistry().makeTest() );
   runner.run(controller);

   // important stuff happens next
   ofstream xmlFileOut("cpptestresults.xml");
   XmlOutputter xmlOut(&result, xmlFileOut);
   xmlOut.write();
}

The assumption here is that your unit tests are built into libraries that are linked with the main function above. To execute the unit tests we add the following to out shell script:

   export PATH=$INSTALL_DIR/bin:$PATH
   export LD_LIBRARY_PATH=$INSTALL_DIR/lib:$LD_LIBRARY_PATH

   # call the cppunit executable
   cd $WORKSPACE
   cppunittests

This results in CppUnit generating file $WORKSPACE/cpptestresults.xml. Now, with the help of a little program called xsltproc and the following little piece of XSLT code, we can translate cpptestresults.xml to testresults.xml in JUnit format.

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <testsuite>
            <xsl:attribute name="errors"><xsl:value-of select="TestRun/Statistics/Errors"/></xsl:attribute>
            <xsl:attribute name="failures">
                <xsl:value-of select="TestRun/Statistics/Failures"/>
            </xsl:attribute>
            <xsl:attribute name="tests">
                <xsl:value-of select="TestRun/Statistics/Tests"/>
            </xsl:attribute>
            <xsl:attribute name="name">from cppunit</xsl:attribute>
            <xsl:apply-templates/>
        </testsuite>
    </xsl:template>
    <xsl:template match="/TestRun/SuccessfulTests/Test">
        <testcase>
            <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
            <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
        </testcase>
    </xsl:template>
    <xsl:template match="/TestRun/FailedTests/FailedTest">
        <testcase>
            <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
            <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
            <error>
                <xsl:attribute name="message">
                    <xsl:value-of select=" normalize-space(Message)"/>
                </xsl:attribute>
                <xsl:attribute name="type">
                    <xsl:value-of select="FailureType"/>
                </xsl:attribute>
                <xsl:value-of select="Message"/>
                File:<xsl:value-of select="Location/File"/>
                Line:<xsl:value-of select="Location/Line"/>
            </error>
        </testcase>
    </xsl:template>
    <xsl:template match="text()|@*"/>
</xsl:stylesheet>

The following call goes into our shell script:

xsltproc cppunit2junit.xsl $WORKSPACE/cpptestresults.xml > $WORKSPACE/testresults.xml

In the configuration page we can now check “Display JUnit test results” and give testresults.xml as result file. As a last step, we can package everything in $WORKSPACE/install_dir into a .tgz file and have Hudson to store it as build artifact. That’s it!

As always, there is room for improvements. One would be to wrap the shell script code above in a separate bash script and have Hudson simply call that script. The only advantage of the approach above is that you can see what’s going on directly on the configuration page. If your project is bigger, you might have more than one CppUnit executable. In this case, you can for example generate all testresult.xml files into a separate directory and tell Hudson to take into account all .xml files there.

Update: For the CMake related part of the above shell script I recently published the first version of a cmakebuilder plugin for Hudson. Check out my corresponding blog post.

About these ads

17 Responses to Using Hudson for C++/CMake/CppUnit

  1. softwarebloat says:

    Great post. Very useful — thanks!

  2. Markus says:

    In the presented example every build is a “clean build” which means that all binary files are deleted before compilation starts.

    If this “clean build” takes too long or you want to have a faster feedback one possibility apart from buying new hardware is to avoid the “clean build” in the majority of cases. Of course it is useful to have a “clean build” from time to be completely sure everything still works.

    The solution I want to present here is to create a separate hudson job “CleanerJob” that does nothing else than deleting the build directory of the “WorkerJob” (the job we don’t want to do a clean build all the
    time) at specific points in time.
    I decided to delete the build directory at lunch time and at midnight.
    For this I used a “Freestyle Hudson Job” and configured it like this:

    I used the “cron-job execution feature”:

    #Lunch time
    45 12 * * *
    #Midnight
    0 0 * * *

    Then I added a bash script that deletes the directory:
    rm -rf <Build_Dir_WorkerJob>

    The last thing to do is to change the script of the “WorkerJob” to avoid a clean build.

    Change this:
    ># we want to have a clean build
    > rm -Rf $BUILD_DIR
    > mkdir $BUILD_DIR
    > cd $BUILD_DIR

    to this:

    if [ ! -d “$BUILD_DIR” ]; then
    mkdir $BUILD_DIR
    fi

    That’s it. The advantages of creating an additional hudson CleanerJob are these:
    * Easy configuration of the “cleans” via the Hudson web-interface
    * Manual clean via the Hudson web-interface possible
    * Manual clean also possible by calling the Hudson “Build URL” of the CleanerJob
    * You can set up Hudson to build the “WorkerJob” every time the “CleanerJob” has been executed (this way the project is built right after the build directory has been deleted)

  3. Markus, thank you for your additional info. It is very useful indeed.

    Please be aware that you might experience strange effects if both jobs happen to run in parallel. To avoid these problems, consider the use of the “locks and latches” plugin for hudson (http://hudson.gotdns.com/wiki/display/HUDSON/Locks+and+Latches+plugin). Using it, you can create a named lock that prohibits the parallel execution of the two jobs.
    If you apply this to your solution, it’s a perfect way to have the speedup of incremental builds and the safety of regular clean builds.

  4. There’s another way as well. It does require some work, but might be worth the effort.

    The Google C++ Testing Framework (googletest) supports producing JUnit-compliant XML reports. In my opinion it also adds the benefit of a cleaner way of defining and running the tests. Tests you define self register, and a test runner main method is provided that you can just link in.

    Read more at http://code.google.com/p/googletest/

  5. […] Hudson. It can be used to build cmake based projects without having to write a shell script (see my previous blog post). Using the scratch-my-own-itch approach I started out implementing only those features that I […]

  6. Jon says:

    I see this comment in the log:
    “The assumption here is that your unit tests are built into libraries that are linked with the main function above.”

    And I really like that idea, but am having problems getting it setup properly. Can you point to an example the CppUnit class setup and and linking things properly in cmake?

    Thanks.

    • volkerkaiser says:

      @Jon: Actually I was planning a blog post on how to setup unit test structures in a c++ project. There are several possibilities and some of them can really hurt you if your project gets bigger. The post should be finished by next week so make sure to come back.

  7. […] much improved as some very useful plugins came into existence. To cover the situation described in my previous post you can now use a combination of the CMake plugin and the CppUnit […]

  8. MMAR says:

    Good xslt …I will try it

  9. voiveadia says:

    Amazing, I did not heard about that till now. Thanks.

  10. A word for C++ programmers that happen to be Hudson users: a few month ago, Gregory Boissinot released the cppunit plugin for Hudson that translates the XmlOutputter result into a JUnit-compatible format. As a consequence, the plugin allows you to directly get your cppunit test results integrated into Hudson in a snap.

    Anyway, good article. I’m planning to write something similar (playing with GNU autotools and heterogenous development environment…)

  11. […] are jenkins plugins which will capture the XML output from cppunit, The plugin to use is […]

  12. Lancer Kind says:

    Beautiful post! Thanks for the great technical writing. update on the Hudson route is that you could use xUnit which is designed to convert from various xUnit report formats to JUnit (cppunit plugin isn’t supported on later Hudson releases). http://wiki.hudson-ci.org/display/HUDSON/xUnit+Plugin

    I’m playing with this now. Unfortunately, the documentation isn’t as clear as yours so there’s a lot of room for another blog article. ;-)

    But I’m glad I’ve got your process here as a backup incase xUnit doesn’t work out.

  13. […] “it’s not a competition”: We try to publish high quality blog entries. But it’s more important to us to tell you about our favorite vegetable (see second metaphor) than to win a pulitzer price for every article. We even try to remind ourselves that we do not compete for the recoginition from our readers (you, in this case!). To be honest here, too: Though it’s not a contest, we issued an internal price for our most read article: Using Hudson for C++/CMake/CppUnit […]

  14. […] Hudson for C++/CMake/CppUnit: schneide.wordpress.com/2008/09/29/using-hudson-for-ccmakecppunit/ Тогда я подмотрел как сохранять результаты теста в […]

  15. xslt code is not complete, at the edges its not precise. kindly correct and help me . i am in need of that code

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 92 other followers

%d bloggers like this: