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:
- Writing Jenkins Pipeline definition (Jenkinsfile)
- 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.
- Configuring Jacoco agent on Tomcat
- 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:
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.
Then enter build name and choose Pipeline.
Finally configure the Pipeline as in the image below.
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
When you select single build on the left you can see coverage report
That's it. Hope you enjoyed the article.
Top comments (2)
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