Source Code Analysis Using SonarQube

When it comes to building an application, we always ensure we develop it according to the business need and also write unit tests to check if what we built works as expected.

But we developers often tend to not check whether the test cases cover every line of code they have written and also if the source code follows development and security best practices.

This is where SonarQube drops in. SonarQube is an open source code analysis tool to inspect code quality, detect bugs, code smells and security vulnerabilities. This helps developers write cleaner and secure code.

In this post, let us take example of the Spring Kafka Telemetry Receiver service, run it through SonarQube community edition, figure out issues and fix them to make the project better.

SonarQube runs on a server and has a gradle plugin that helps integrate Sonar Scanner within the gradle build. We will use the same. Let's begin.

Run SonarQube as Docker Container

Bring up your docker service and lets start the SonarQube server on our local machine.

docker run -d --rm --name sonarqube -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p 9000:9000 sonarqube:community

This will pull the SonarQube community edition image and start the container. It will be accessible on http://localhost:9000 with default login credentials being admin/admin.

SonarQube projects dashboard
Gradle Dependencies

Now, let's add the SonarScanner plugin to our build.gradle file. SonarQube doesn't run code coverage on its own, it depends on test reports generated by Jacoco.

So along with SonarQube, we also add Jacoco plugin to generate test reports based on our JUnit 5 Jupiter unit tests.

plugins {
    id "java"
    id "jacoco"
    id "org.springframework.boot" version "${springBootVersion}"
    id "org.sonarqube" version "${sonarQubeVersion}"
}
test {
    useJUnitPlatform()
    finalizedBy jacocoTestReport
}
jacocoTestReport {
    reports {
        xml.enabled true
        html.enabled true
        csv.enabled false
        xml.destination file("${buildDir}/jacoco/xml/jacoco.xml")
        html.destination file("${buildDir}/jacoco/html")
    }
    dependsOn test
}

sonarqube {
    properties {
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.exclusions", "**/Application.java, **/dto/**"
        property "sonar.java.source", "${project.sourceCompatibility}"
        property "sonar.java.target", "${project.targetCompatibility}"
        property "sonar.junit.reportsPath", "${buildDir}/reports/tests"
        property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/jacoco/xml/jacoco.xml"
    }
}
tasks.sonarqube.dependsOn test

Observe the configurations for the tasks. We are excluding Application.java from analysis as there is only the Spring boot application start in that class and also excluding the DTOs since they are POJO classes.

Run SonarQube Analysis

Now that we have added all the dependencies and configured SonarQube to read Jacoco xml report, we can go ahead and run the analysis.

./gradlew sonarqube

One the task completes, on you SonarQube dashboard, you should be able to see the list of all the issues it found with the code along with the code coverage metric.

SonarQube analysis of Spring Kafka Telemetry Receiver
Code smells in Spring Kafka Telemetry Receiver

That's not good isn't it. Now we can go through each of these issues one by one, resolving them and then run the analysis again.

The beauty of it is that, it doesn't just say there is an issue. It also give you explanations of why it's an issue and how to go about fixing it. Below is an example.

SonarQube code smell explanation

After going through the report, I updated the source code with the fixes to the above issue, especially to improve code coverage by adding more test cases and also added "awatility" library to replace Thread.sleep().

You can find the updated source code on the git repository.

Running the analysis after fixing the issue, here is the result.

SonarQube analysis report of Spring Kafka Telemetry Receiver spring boot application

You can see, we cleared all our code smells and also one potential security issue with the code.

Although SonarQube only requires Jacoco xml report, since we enabled html, we can check out that report as well at build/jacoco/html/index.html.