Monday, April 9, 2012

Continuous Integration with Jenkins, Mercurial and CppUnit on C++

Hello again!! Today I am going to talk about Jenkins, an open source tool that enables the continuous integration and delivery for our projects. As usual we will explain on this post how to set up a basic configuration and have the tool working into a local environment, if you are looking for a more complex configuration you can download here for free the book 'Jenkins the definitive guide'.

Basically what we are following with the continuous integration is to set up an environment that periodically and automatically check out our code, builds it and pass a set of regression/unit tests.

Jenkins provides us with a set of features that allows that and much more, as automatic mails in case of broken builds, dashboards showing the tests results, CVS/Mercurial and others version control systems integration and on the top of everything a friendly web based interface allowing everybody to check the results and manage the system.

A. Installing Mercurial on Debian Squeeze

1. Download here the last release for debian

2. Add the key:

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -


3. Install the following dependencies:

sudo apt-get install daemon


4. Install the package we downloaded on the step number 1:

sudo dpkg -i jenkins_1.454_all.deb


5. Logs & PID. By default Jenkins is executed as a stand-alone server, you can find the logs and the process id on the following files:

/var/log/jenkins/jenkins.log
/var/run/jenkins/jenkins.pid

6. Jenkins is configured by default to listen on the port 8080, if you fulfilled the previous steps, you should be able to see your jenkins interface by typing 'localhost:8080' on your favorite web explorer:



B. Linking Jenkins with our Project across Mercurial


The way Jenkins interacts with our source code is across mercurial, once Jenkins is properly configured it checks out our code, into a temp folder, builds the source code and executes the test that we have previously configured.

First of all you will have to install and configure mercurial on your machine. You can have a look here in order to know how to do it.

1. Putting our code under mercurial:

Since the objective of this post is not learn how to use mercurial, we will create a 'local' repository in our working directory (in my case /home/javier/workspace/workspace64/workspaceSharedLibrary) by executing the following command from the previous folder:

hg init


Now our source code is under mercurial and therefore can be accessed by Jenkins, let's see how.

2. Installing the Mercurial Plugin on Jenkins:

The mercurial plugin is not installed by default. From the initial Jenkins web page, click on 'Manage Jenkins', and afterwards click on 'Manage Plugins'. Under the available tab, you should be able to find 'Jenkins Mercurial plugin'. Check it and click on the button 'Install without restart'.

C. Configuring a new job

Now we have everything we need to configure our first 'job'. In Jenkins world, a 'job' is a set of task (that can be defined on a shell script) that are automatically executed within a configurable period, typically those tasks are related with building and testing.

From the initial page (localhost:8080) click on 'New job'. Give a name to your (in my case 'My_firs_job') select 'Build a free-style software project' and click 'ok', a new page allowing configure your job should be displayed. On the first part of the screen we are configuring the Mercurial repository (the local one) that jenkins must check out:


By scrolling down, we set up the frequency of the job. By setting 'Poll SCM' and putting ***** on the Schedule we are indicating that each minute, jenkins must check if there have been changes on the code and if it is the case it must executes the job. In this case the build is defined on the shell file 'home/javier/SANDBOX/Jenkins/build'. We will see the content of this file on the next section.


Finally, by scrolling down again, we can set the list of emails that must be notified in case that a build is not broken.



D. Create the build file ( /home/javier/SANDBOX/Jenkins/build)

The most basic build file is the one that executes the makefile that eclipse generates automatically. The variable 'WORKSPACE' is set up automatically by jenkins and defines the temporally directory where the code is check out.

#!/bin/bash
echo "*********building************"
echo $WORKSPACE
cd $WORKSPACE/InitialTest/Debug
echo $PWD
make clean
make


E. Configure the mail


In order to allow mail sending we have to link our jenkins platform with a mail server. In this case I will use my gmail acount for this end.

From the initial jenkins page (localhost:8080) click on 'Manage Jenkins' and then on 'Configure System'. At the bottom of the page you can set E-mail Notification parameters:




D. Executing the job


Now everything is configured and you can manually execute your job:

From the initial Jenkins page, select your job and on the left side of the page click on 'Build now'. A new item will be created on the 'Build History':



By clicking on the Build History item, you can enter to the details of the build. The most interesting information can be found on the 'Console Output' :

Started by user anonymous
Building in workspace /var/lib/jenkins/jobs/My_first_job/workspace
[workspace] $ hg showconfig paths.default
[workspace] $ hg pull --rev default
[workspace] $ hg update --clean --rev default
6 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
[workspace] $ hg log --rev 1633c8b2cc6ab2fd1b40a594eb3cb21b1b9277f6
[workspace] $ hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 1633c8b2cc6ab2fd1b40a594eb3cb21b1b9277f6
[workspace] $ /bin/sh -xe /tmp/hudson7862122761400994217.sh
+ /home/javier/SANDBOX/Jenkins/build
*********building************
/var/lib/jenkins/jobs/My_first_job/workspace
/var/lib/jenkins/jobs/My_first_job/workspace/InitialTest/Debug
rm -rf  ./src/InitialTest.o  ./src/InitialTest.d  InitialTest


Building file: ../src/InitialTest.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/javier/workspace/workspace64/workspaceSharedLibrary/MySharedLibrary" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/InitialTest.d" -MT"src/InitialTest.d" -o "src/InitialTest.o" "../src/InitialTest.cpp"
../src/InitialTest.cpp: In function ‘int main()’:
../src/InitialTest.cpp:19: warning: unused variable ‘value’
Finished building: ../src/InitialTest.cpp


Building target: InitialTest
Invoking: GCC C++ Linker
g++  -o "InitialTest"  ./src/InitialTest.o   -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_features2d -lopencv_calib3d
Finished building target: InitialTest
Finished: SUCCESS


E. Setting Green Balls as success indicator:

By default Jenkins indicates a successful build with a blue ball. If you (like me) consider that green color is more appropriated for this end, you just need to install the 'Green Balls' pluging;

From the initial Jenkins page click on 'Manage Jenkins' then on 'Manage Plugins' and under 'Available' tab find the 'Green Balls' plugin. Select it and click on 'Install without restart'. In order to have the plugin working, you will need to clean the cache of your explorer.

F. Unit Tests


As final step we are going to set up a unit test project that will be automatically executed (as the build) each time that someone commit a change in the central repository.

The first thing we need is to install 'CppUnit'. CppUnit is an open-source project that provides us with a set of utilities allowing include statements like 'assert' in our code. You can find more information about CppUnit in the official project page:

http://sourceforge.net/projects/cppunit/

More information and examples can be found on the CppUnit cookbook:

http://cppunit.sourceforge.net/doc/1.8.0/cppunit_cookbook.html

1. Download and Install.

From the project page, download and untar the last version of the project (1.12.1).

From the untar directory, execute the following commands:



./configure
make
sudo make install




2. Create your test project.

Using eclipse, create a new C++ project and add the following libraries:

libcppunit.so
libdl.so

If you do not include the libdl.so library, you will receive the following errors at building time:


/usr/local/lib/libcppunit.so: undefined reference to `dlsym'
/usr/local/lib/libcppunit.so: undefined reference to `dlopen'
/usr/local/lib/libcppunit.so: undefined reference to `dlclose'


Your project settings should look like this:



3. Make a shell executing the test project and transforming the results

I will dedicate a whole post to CppUnit, but by the time being we will consider enough to have a project working and generating a resulting report test (you can find how to do this on the CppUnit cookbook)

Once we have developed our test project we just need to create a new shell script (/home/javier/SANDBOX/Jenkins/tests) that runs it and transforms the result into a new report 'readable' by Jenkins:





 #!/bin/bash
echo "*********building tests project************"
echo $WORKSPACE
cd $WORKSPACE/CppUnitProject/Debug
echo $PWD
make clean
make 
$WORKSPACE/CppUnitProject/Debug/CppUnitProject
xsltproc /home/javier/SANDBOX/Jenkins/transform.xsl $WORKSPACE/CppUnitProject/Debug/cpptestresults.xml > $WORKSPACE/testresults.xml



In the previous script we are just executing the auto-generated (by Eclipse) make file and applying a xslt transformation that generates 'testresults.xml' from 'cpptestresults.xml'. In order to do that you will need the transformation file (in our case /home/javier/SANDBOX/Jenkins/transform.xsl) with the following content:






<?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>


4. Setting jenkins to execute the new shell

Once everything is in place we just need to include a new shell in our Job. From the initial Jenkins page click on your existing job and on menu placed on the left, click on configure. On the build section click on 'Add Build Step' and select 'Execute shell'. Set the location of our script (in my case /home/javier/SANDBOX/Jenkins/tests) and save the changes.



Now when building our job and checking the console output you should see that the test unit project is executed:


*********building tests project************
/var/lib/jenkins/jobs/My_first_job/workspace
/var/lib/jenkins/jobs/My_first_job/workspace/CppUnitProject/Debug
rm -rf  ./src/CppUnitProject.o ./src/MyClass.o ./src/MyClassTest.o  ./src/CppUnitProject.d ./src/MyClass.d ./src/MyClassTest.d  CppUnitProject

Building file: ../src/CppUnitProject.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/CppUnitProject.d" -MT"src/CppUnitProject.d" -o "src/CppUnitProject.o" "../src/CppUnitProject.cpp"
Finished building: ../src/CppUnitProject.cpp

Building file: ../src/MyClass.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/MyClass.d" -MT"src/MyClass.d" -o "src/MyClass.o" "../src/MyClass.cpp"
Finished building: ../src/MyClass.cpp

Building file: ../src/MyClassTest.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/MyClassTest.d" -MT"src/MyClassTest.d" -o "src/MyClassTest.o" "../src/MyClassTest.cpp"
Finished building: ../src/MyClassTest.cpp

Building target: CppUnitProject
Invoking: GCC C++ Linker
g++  -o "CppUnitProject"  ./src/CppUnitProject.o ./src/MyClass.o ./src/MyClassTest.o   -lcppunit -ldl
Finished building target: CppUnitProject



Resources

http://jenkins-ci.org/
http://schneide.wordpress.com/2008/09/29/using-hudson-for-ccmakecppunit/
http://cppunit.sourceforge.net/doc/1.8.0/cppunit_cookbook.html#cppunit_cookbook
http://www.wakaleo.com/books/jenkins-the-definitive-guide

21 comments:

  1. You can replace periodic polls to the repository by commit hooks as shown here:
    http://stackoverflow.com/questions/1797074/local-executing-hook-after-a-git-push#answer-3466589

    or here:
    https://bitbucket.org/dromanov/testing_ground/wiki/Use%20web-hook%20to%20trigger%20CI%20build%20and%20test

    The examples are for git, but Mercurial can do everything as well, just google for "bitbucket web hook" or similar stuff.

    Thank you for your hints!

    ReplyDelete
    Replies
    1. Very good contribution! Thanks for this tip :)

      Delete
  2. Hi, Jenkins can not execute my build script.
    It says "Permission denied"
    build.sh is under git, so it is pulled everytime on schedule.
    Its file permission described by git clone operation.
    Its owner is jenkins user.

    ReplyDelete
  3. This is very helpfull Blog!! Thankyou.
    DevOps Training

    ReplyDelete
  4. I am really happy with your blog because your article is very unique and powerful for new reader.Prefer to study this kind of material. Nicely written information in this post,the quality of content is fine and the conclusion is lovely. Things are very open and intensely clear explanation of issues. PHP Training in Chennai | Certification | Online Training Course | Machine Learning Training in Chennai | Certification | Online Training Course | iOT Training in Chennai | Certification | Online Training Course | Blockchain Training in Chennai | Certification | Online Training Course | Open Stack Training in Chennai |
    Certification | Online Training Course

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. https://linuxtortures.blogspot.com/2012/04/continuous-integration-with-jenkins.html?showComment=1615634499836#c6382855856246794470

    ReplyDelete
  7. Samanta Computer is providing up to 90% offer on Gaming Graphics Card Limited time i bought a Graphics last night.

    ReplyDelete
  8. Are you Worried to Know Intel 10th Gen Core i3 10100F processor in bd Price in Bangladesh? let’s Discuss the Price of Intel 10th Gen Core i3 10100F Processor.Intel 10th Gen Comet Lake Core i3 10100F Processor : Model – Intel Core i3 10100F, Code-Name – Comet Lake, CPU Cooler – PCG 2015C, Generation – 10th, Base Frequency – 3.60GHz, Turbo Frequency Max. –

    ReplyDelete
  9. Are you Worried to Know Intel 10th Gen Core i3 10100 processor in bd Price in Bangladesh? let’s Discuss the Price of the Intel 10th Gen Core i3 10100 Processor. This processor comes with a new breed that come with an enabled integrated GPU, so a separate graphics card is not required for its functionality. This new 10th gen Comet Lake microarchitecture is manufactured with the 14nm process that comes with four cores but lacks in HyperThreading. As this chip is updated to the latest BIOS revision, it nicely fits into any Intel 300-series motherboard. Focusing on this, all the major motherboard manufacturers have already started BIOS updates for their 300-series lineup

    ReplyDelete
  10. Are you planning to Buy Intel 10th Gen Core i3 10105F processor in bd ? Let’s Discuss the price of the Intel 10th Gen Core i3 10105F Processor in Bangladesh. This new 10th gen Comet Lake microarchitecture is manufactured with the 14nm process that comes with four cores but lacks HyperThreading. As this chip is updated to the latest BIOS revision, it nicely fits into any Intel 400 and 500 series motherboard.

    ReplyDelete
  11. Are you worried to know AMD Ryzen 5 3600 Processor in Bangladesh (bd)? Let’s discuss the price of the AMD Ryzen 5 3600 Processor price in BD. The 3rd Generation AMD Ryzen™ desktop processors are built on the cutting-edge 7nm process, delivering a generational leap in performance and power efficiency. The new 7nm Zen 2 architecture features multiple upgrades to boost CPU and APU performance, including AMD Sense MI technology is an intelligent suite of algorithms that use artificial intelligence (AI) to predict what both the application and user want or need next

    ReplyDelete

  12. Are you worried to know AMD Ryzen 5 5600X Processor in bd price in Bangladesh? Let’s discuss the price of the AMD Ryzen 5 5600X Processor price in Bangladesh. AMD Ryzen 5 5600X Processor price deliver exceptional performance, high application responsiveness, and a host of new features for today’s modern computing experiences. Unlocked processor operating parameters allow you to overclock your CPU from the factory. But don’t stop there – AMD Store MI technology combines the speed of your SSD with the capacity of your hard drive into a single, fast, easy-to-manage drive letter for faster system boot times and speedy data access

    ReplyDelete
  13. Are you worried to know Processor price in Bangladesh? Let’s discuss the price of the AMD Ryzen 5 Pro 4650G Processor in BD. Are you looking for a powerful and affordable processor? Look no further than the AMD Ryzen 5 Pro 4650G! This processor offers great performance

    ReplyDelete
  14. Are you Worried to Know Asus Dual GeForce GTX 1650 4GB DDR5 Graphics Card Price in Bangladesh? let’s Discuss Asus Dual GeForce GTX 1650 4GB DDR5 Graphics Card Price in BD. GeForce GTX 1650 4GB GDDR5 graphics card with ultra-fast performance and great power efficiency. The perfect upgrade to advanced gaming and productivity, the GeForce GTX 1650 is built on the cutting-edge NVIDIA Turing architecture for amazing performance and stunning visuals. GeForce GTX 1650 OC Edition 4GB GDDR5. The GeForce GTX 1650 is built with the breakthrough graphics performance of the award-winning NVIDIA Turing architecture

    ReplyDelete
  15. Are you Worried to Know Asus Dual GeForce GTX 1650 4GB DDR5 Graphics Card Price in Bangladesh? let’s Discuss Asus Dual GeForce GTX 1650 4GB DDR5 Graphics Card Price in BD. GeForce GTX 1650 4GB GDDR5 graphics card with ultra-fast performance and great power efficiency. The perfect upgrade to advanced gaming and productivity, the GeForce GTX 1650 is built on the cutting-edge NVIDIA Turing architecture for amazing performance and stunning visuals. GeForce GTX 1650 OC Edition 4GB GDDR5

    ReplyDelete
  16. Women's Indian and Pakistani clothes [Shops] in the UK & Fashion are as varied and exciting as the women who wear it. From formal to casual, sexy to elegant, we've got everything you need to look great in your clothes. We offer top brands like Cole Haan, Michael Kors and Charles David at discount prices so you can shop online with confidence!

    ReplyDelete
  17. Bandicam License Key is an application that allows you to record everything that happens on your screen, including any program that usesKeymaker Bandicam

    ReplyDelete
  18. Portraiture Plugin For Photoshop Cc Crack Torrent Portraiture is one of the most popular plugins for Adobe Photoshop Imagenomic Portraiture Crack

    ReplyDelete
  19. Are you setting up your kitchen and looking for the most relevant products and accessories? This is the page for you, we've got all the kitchenware items you need to start creating your own bakery, kitchen or whatever it is you want.

    ReplyDelete