loading...

Jenkins pipeline for remote Jacoco test coverage

piczmar_0 profile image Marcin Piczkowski Updated on ・4 min read

Part of every product development is proper testing of the application.
There are numerous ways of testing it and explaining all of them is definitely a subject for several blog posts.

In this post I will concentrate on a particular scenario.
We want to run integration test using Maven build against application deployed on remote Tomcat. Surely we could use embedded Tomcat, but let's say we want to verify that it runs properly in its target environment, e.g. staging where different other components may require proper configuration, like database, other services etc.

In this post, I will explain how to configure Jenkins build using the descriptive pipeline. The build will at some point download test coverage data from remote Tomcat server using Jacoco plugin.

I will use a sample Spring Boot application which has REST endpoint.
We're going to query this endpoint from our functional tests. Here is the project.

There are several parts involved in this configuration:

  1. Writing Jenkins Pipeline definition (Jenkinsfile)
  2. Configuring Jenkins server to access remote Tomcat server using SSH, e.g. we want to copy the latest package to Tomcat, start Tomcat before functional tests will run and then stop it at the end.
  3. Configuring Jacoco agent on Tomcat
  4. Configuring Jenkins build which will pull the project from Github repository and start the build. Then we would like to have Jacoco reports visible in build dashboard.

Let's start from the Pipeline definition.
Jenkins Pipeline is a very nice feature which allows configuring builds from a text file. I like this idea mostly because it allows storing build configuration together with source code in the same repository and control versioning. You can see the complete Jenkinsfile here.
I just wanted to give you a feeling of what you can do with it.
First, you can manage which tools you will need for the build.

    tools {
        maven 'mvn_3.5'
        jdk 'JDK1.8'
    }

These are the names which you used in Jenkins Global Tool Configuration.
E.g. for JDK it would like like below:

JDK configuration in Jenkins

Then you can define a list of stages, each executing several steps.

The stage below is running maven command which produces WAR file to deploy on Tomcat.

     stages{
         ...

        stage ('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
         ...
     }

Next, we can execute shell commands.

        stage ('Deploy') {
            steps {
                sh 'ssh tomcatuser@tomcathost rm -fR ${TOMCAT_HOME}/webapps/RestDemo-0.0.1*'
                sh 'ssh tomcatuser@tomcathost ls ${TOMCAT_HOME}/webapps/'
                sh 'scp target/RestDemo-0.0.1-SNAPSHOT.war tomcatuser@tomcathost:${TOMCAT_HOME}/webapps/'
            }
        }

The commands above use SSH to invoke remote commands:

  • removing old artifacts deployed on Tomcat
  • listing content of Tomcat webapps folder for debugging purposes
  • copying new artifact to Tomcat. They will be deployed when Tomcat starts.

As you see the Jenkinsfile is very straightforward and allows quick configuration of the entire pipeline. Definitely more friendly way than clicking through Jenkins UI.

Our build is running remote commands via SSH. To allow it we have to give Jenkins Host permission to connect to Tomcat Host through SSH.
This is very easy. I will skip how to install SSH on both hosts. It can be easily found in the internet.
Then we need to generate SSH key on Jenkins Host (if does not exist) but use blank passphrase (otherwise we cannot input passphrase in non-interactive mode when pipeline runs and it will fail)

cd ~/.ssh
ssh-keygen -t rsa

and confirm default answers.
This will create two files: ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub.
The last one is the public key. We need to take content of this file and copy it on Tomcat server to file ~/.ssh/authorized_keys

Now we can test connection and run from Jenkins Host

ssh tomcatuser@tomcathost

Where tomcatuser is an existing user on Tomcat Host who has permission to start/stop Tomcat and tomcathost is (as you probably guessed ;)) Tomcat Host hostname or IP address.

On Tomcat we need to update configuration to allow running Jacoco agent.
This is the tinny Java program which will start when Java Virtual Machine starts, instrument deployed classes and gather information required to calculate coverage data on runtime, when we query REST endpoint.
When we will run Jenkins build it will download this coverage data through TCP/IP, because Agent on Tomcat is listenning on a port.

This is a line which needs to be added on Tomcat Host in $TOMCAT_HOME/bin/catalina.sh at the very beginning of the file

JAVA_OPTS="-javaagent:/opt/jacoco/jacocoagent.jar=output=tcpserver,address=*,port=10001"

It needs to have path to jacocoagent.jar which you download from Jacoco site. You can find it in downloaded ZIP in lib folder.
It needs also port number. You can use any free port. This is a port on which Maven Jacoco Plugin will connect to download coverage data.

The last, but not least part, is setup of build on Jenkins.
Here we go..
First create a new build.

Create new Jenkins build

Then enter build name and choose Pipeline.

Choose Pipeline type

Finally configure the Pipeline as in the image below.
Configure

All you need to do is to specify Github repo and the path to Jenkinsfile relative to project root. It is a good practice to put the file at the top of your project (next to pom.xml) because it simplifies stages definition - all paths in command can be given relative to root, e.g. mvn .. command. Otherwise it will need more twicks.

Last part is to test the build.
Let's run it manually. Then we can setup any triggers we want just like for any other Jenkins build.

When the build completes you will see a nice breakdown of stages and can see coverage charts

Build Dashboard

When you select single build on the left you can see coverage report

Coverage reports

That's it. Hope you enjoyed the article.

Posted on by:

piczmar_0 profile

Marcin Piczkowski

@piczmar_0

Software engineer with over 10 years experience in different technology stacks, architecting, developing, CI/CD and leading teams. Currently working with Java, Node.JS and Serverless

Discussion

pic
Editor guide
 

Thank you!
Could you record a video how you did it? It would be very helpful who not very familiar with these tools.

 

thanks, I'll do when I have a while