SonarQube scanner cannot scan Kotlin Jacoco coverage - sonarqube

My gradle task jacocoTestReport() works properly and it generates jacocoTestReport.xml. It contains kotlin coverage as expected.
However, if I use SonarQube Scanner 4.0 Jenkins plugin, it fails to send Kotlin part of coverage report. So I cannot find kotlin coverage on Sonarqube dashboard.
I think there is something wrong with my Analysis properties, but I cannot find it.
# required metadata
sonar.projectKey=aaaaa123
sonar.projectName=aaaaa123
sonar.projectVersion=${VERSION_MAJOR}.${VERSION_MINOR}
# disable sonar.language parameter to triggering multi-language analysis
#sonar.language=java
# path to test source directories
sonar.sources=mypicker/src/main/java
sonar.test.inclusions=mypicker/src/test/java
sonar.java.binaries=mypicker/build/intermediates/javac/debug,ext/mypicker/build/tmp/kotlin-classes/debug
#sonar.junit.reportPaths=mypicker/build/test-results/testDebugUnitTest
#sonar.jacoco.reportPaths=mypicker/build/jacoco/testDebugUnitTest.exec
sonar.coverage.jacoco.xmlReportPaths=mypicker/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
sonar.sourceEncoding=UTF-8
sonar.java.source=1.8
sonar.ws.timeout=300
sonar.findbugs.timeout=3600000
My gradle task code which works perfectly is:
task jacocoTestReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
def javaDebugTree = fileTree(dir: "${buildDir}/intermediates/javac/debug", excludes: fileFilter)
def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter)
def mainSrc = "${project.projectDir}/src/main/java"
sourceDirectories.from = files([mainSrc])
classDirectories.from = files([javaDebugTree, kotlinDebugTree])
executionData.from = files("${buildDir}/jacoco/testDebugUnitTest.exec")
}
Sonarqube: 6.7.5 (build 38563)
SonarQube Scanner: 4.0.0.1744

Related

How to get Jacoco reports for the Karate test feature files using gradle

How to get Jacoco reports for the Karate test feature files using Gradle.
My project is a Gradle project and I am trying to integrate jacoco report feature in my project for the karate tests. The server is running in my local on 8080 port.
I am doing the following way to generate jacoco report and please let me know is my approach correct and also give me a solution to get the jacoco report for the gradle project.
1) First I am trying to generate jacoco execution data with the help of jacocoagent.jar as follows with a Gradle task:
java -javaagent:/pathtojacocojar/jacocoagent.jar=destfile=/pathtojocofile/jacoco.exec -jar my-app.jar
2) Next, I am running a Gradle task to generate the report
project.task ('jacocoAPIReport',type: org.gradle.testing.jacoco.tasks.JacocoReport) {
additionalSourceDirs = files(project.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(project.sourceSets.main.allSource.srcDirs)
classDirectories = files(project.sourceSets.main.output)
executionData = fileTree(dir: project.projectDir, includes: ["**/*.exec", "**/*.ec"])
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
onlyIf = {
true
}
doFirst {
executionData = files(executionData.findAll {
it.exists()
})
}
}
project.task('apiTest', type: Test) {
description = 'Runs the api tests'
group = 'verification'
testClassesDirs = project.sourceSets.apiTest.output.classesDirs
classpath =
project.sourceSets.apiTest.runtimeClasspath
useJUnitPlatform()
outputs.upToDateWhen { false }
finalizedBy jacocoAPIReport
}
I don't see any of my application's classes in the jococo.exec file. I think, bcz of that I am always getting the coverage report as 0%.
The server is running in my local on 8080 port.
I don't think that is going to work. Depending on how your code is structured you need to instrument the code of the server.
I suggest trying to get a simple unit test of a Java method to work with Gradle. If that works, then use the same approach for the server-side code and it will work.

CorDapp JaCoCo Code Coverage

I have a Corda based project with several CorDapp sub projects. I've been looking to add JaCoCo code coverage to this project. I'm looking to have a single code coverage report draw in an aggregate report of all the subproject JaCoCo reports.
To add JaCoCo to a maven project with several maven sub projects, I followed this blog entry https://lkrnac.net/blog/2016/10/aggregate-test-coverage-report/. After we ran the build ./gradlew clean test and got our reports, one of our team members noted that the whitelists weren't being created properly anymore when we ran ./gradlew clean deployNodes.
I've gone back to the base Kotlin CorDapp template found here https://github.com/corda/cordapp-template-kotlin to rule out if it's something we've done wrong with our project structure/gradle. Without JaCoCo added, I see all the whitelist entries I would expect. Once I add the JaCoCo code, I only see the 5 default Corda whitelist entries, and none of my added contract entries.
I'm using JaCoCo version 0.8.1 and coveralls version 2.6.3. The changes I've made are all within the build.gradle file for the root directory cordapp-template-kotlin:
subprojects {
repositories {
mavenCentral()
}
apply plugin: 'jacoco'
apply plugin: 'java'
group = 'net.lkrnac.blog'
version = '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
testCompile("junit:junit:4.12")
}
jacoco {
toolVersion = jacoco_version
}
//command for generating subproject coverage reports
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
}
}
def publishedProjects = subprojects.findAll()
task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates an aggregate report from all subprojects'
dependsOn(publishedProjects.test)
additionalSourceDirs = files(publishedProjects.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(publishedProjects.sourceSets.main.allSource.srcDirs)
classDirectories = files(publishedProjects.sourceSets.main.output)
executionData = files(publishedProjects.jacocoTestReport.executionData)
doFirst {
executionData = files(executionData.findAll { it.exists() })
}
reports {
html.enabled = true // human readable
xml.enabled = true // required by coveralls
}
}
coveralls {
sourceDirs = publishedProjects.sourceSets.main.allSource.srcDirs.flatten()
jacocoReportPath = "${buildDir}/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
}
tasks.coveralls {
dependsOn jacocoRootReport
}
I believe that the problem is coming from simply adding a task where JacocoReport as a parameter. Any thoughts how I could proceed to have both code coverage, along with building my whitelists correctly?
I have managed to find how to fix the coverage/whitelisting issue. I started stripping away what seemed to be unnecessary code within the subprojects spec, and found that removing everything except the apply plugin:, jacoco, and jacocoTestReport commands yielded both the root Jacoco code coverage, along with the necessary whitelisting. I didn't need to change any of the other code above to get the whitelisting to work.
For reference, subprojects now looks like this:
subprojects {
apply plugin: 'jacoco'
apply plugin: 'kotlin'
jacoco {
toolVersion = jacoco_version
}
//command for generating subproject coverage reports
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
}
}

Gradle, Kotlin, Junit5 and Jacoco - 0% coverage reported

We would like to use Gradle in conjunction with Kotlin and Jacoco (+JUnit 5) for generating a code coverage report.
Our project directory tree looks as follows:
project/{src,test}/main/kotlin ...
Our build.gradle file looks as follows:
jacoco {
toolVersion = "0.7.9"
reportsDir = file("$buildDir/reports")
applyTo junitPlatformTest
}
jacocoTestReport {
group = "Reporting"
description = "Generate Jacoco coverage report."
classDirectories = fileTree(
dir: "$buildDir/classes/kotlin/main"
)
def coverageSourceDirs = [
"src/main/kotlin"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("$buildDir/jacoco/junitPlatformTest.exec")
reports {
xml.enabled = true
html.enabled = true
csv.enabled = true
}
}
test {
jacoco {
append = false
destinationFile = file("$buildDir/jacoco/junitPlatformTest.exec")
includeNoLocationClasses = true
}
}
test.dependsOn junitPlatformTest
With this configuration, Jacoco generates a html report and puts it under build/reports/test/html. However, it shows me 0% coverage. This should not be the case, because I have one test case that excercices all methods for a single dummy class in the project.
I went through several posts such as:
http://vgaidarji.me/blog/2017/12/20/how-to-configure-jacoco-for-kotlin-and-java-project/
Jacoco is reporting 0 coverage of Kotlin classes by unit tests, in an Android project
JaCoCo returning 0% Coverage with Kotlin and Android 3.0
However, I could not quite find a solution that worked for me, yet.
I recently hit this issue when upgrading form junit 4 -> 5. In my case I had to re-arrange the declaration of the dependencies as outlined here. If you change to this format you should see the coverage reported correctly again without having to change any other configuration.
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

gradle jacoco plugin not generate exec files

I've done gradle migration from gradle 3.5 to gradle 4.6. After migration exec files have stopped generated. '/build' folder doesn't contain 'jacoco' folder.
If I run gradle command with -- debug it writes in log :
[org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter]
Skipping task ':common:jacocoTestReport' as task onlyIf is false.
Here is part of gradle script:
subprojects {
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: 'idea'
...
jacocoTestReport {
reports {
xml.enabled true
csv.enabled false
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['**/dto/**', '**/endpoint/**','**/enpoints/**', '**/spring/**',
'**/servlet/**','**/handler/**', '**/jpa/**', '**/filter/**', '**/events/**', '**/dao/**',
'**/exception/**', '**/http/**', '**/jdbc/**', '**/bigquery/**', '**/enums/**',
'**/repository/**', '**/combination/**', '**/datastore/**', '**/cassandra/**',
'**/google/**', '**/exceptions/**', '**/logging/**', '**/JavaGeneratedContext.java', '**/Q*.java'])
})
}
}
test {
enabled = !skipTests
allJvmArgs = [
'-Dfile.encoding=utf-8'
]
useJUnit {
excludeCategories 'com.severn.common.test.IntegrationTest'
}
/*jacoco {
enabled = true
destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
}*/
finalizedBy jacocoTestReport
}
...
}
Make sure:
1) Your debug info is enabled during compile in your top level Gradle file (allprojects { ... } ). See here for more info: Jacoco Unit and Integration Tests coverage - individual and overall
tasks.withType(Compile) {
options.debug = true
options.compilerArgs = ["-g"]
}
2) Try removing the whole Jacoco configuration from the test task (make sure you place the .exec file if generated in the default location where jacocoTestReport task expects it). Make sure test task is running (and not getting excluded somehow). For testing purpose (to narrow down this .exec not getting created issue), you can force jacocoTestReport task to dependOn test task.
tasks.withType(Test) {enabled = true}
3) See latest Gradle 4.6 bundle (tar/zip) for Jacoco examples for a Java single/multi level project to get hint.
PS: Default JaCoCo version upgraded to 0.8.0 See if forcing this version within jacoco block helps.
https://docs.gradle.org/4.6/release-notes.html
The JaCoCo plugin has been upgraded to use JaCoCo version 0.8.0 by default.

Gradle Jacoco - coverage reports includes classes excluded in configuration

I added to a project a set of sources that don't have tests and I don't want them spoil my test coverage statistics. I configured Jacoco in the next way :
test {
jacoco{
excludes = ['org/bla/**']
includes = ['com/bla/**']
append = false
}
}
jacocoTestReport {
dependsOn test
description = "Generate Jacoco coverage reports after running tests."
reports {
xml.enabled true
html.enabled true
}
classDirectories = fileTree(dir: 'build/classes/main', include: 'com/bla/**')
sourceDirectories = fileTree(dir: 'scr/main/java', include: 'com/bla/**')
}
But anyway, when generating the report, Jacoco also includes classes from org.bla
Can someone help me ?
EDIT
After some debugging, it appears that all default outputs are added to org.gradle.testing.jacoco.tasks.JacocoReport#classDirectories in a private method org.gradle.testing.jacoco.plugins.JacocoPlugin#addDefaultReportTasks
That's visible when using such code :
jacocoTestReport {
classDirectories = files('build/classes/main/com/bla')
println("-----------------------------------------------------------")
getAllClassDirs().each { File file ->
println(file.absolutePath)
}
println("-----------------------------------------------------------")
getAdditionalClassDirs().each{ File file ->
println(file.absolutePath)
}
}
jacocoTestReport << {
println("-----------------------------------------------------------")
getAllClassDirs().each { File file ->
println(file.absolutePath)
}
println("-----------------------------------------------------------")
getAdditionalClassDirs().each{ File file ->
println(file.absolutePath)
}
}
Output
-----------------------------------------------------------
<path_here>\build\classes\main\com\bla
-----------------------------------------------------------
....more text here
-----------------------------------------------------------
<path_here>\build\classes\main\com\bla
<path_here>\build\classes\main
<path_here>\build\resources\main
-----------------------------------------------------------
So - the question is : is it possible to override somehow org.gradle.testing.jacoco.plugins.JacocoPlugin#addDefaultReportTasks method, or override completely org.gradle.testing.jacoco.plugins.JacocoPlugin class ?
Ok, found a workaround :
jacocoTestReport.doFirst{
classDirectories = files('build/classes/main/com/bla')
}
This overrides classDirectories set by JacocoPlugin class.
If you have a task names something other than
test
that runs unit tests, you should be able to generate the report adding the following task to your build.gradle file:
jacocoTestReport {
group = "Reporting"
description = "Generates Jacoco coverage reports for unit tests"
executionData = files('build/jacoco/unitTest.exec')
reports {
html.destination = 'build/reports/coverage'
}
}
This needs to be called explicitly after the task to run unit tests, e.g:
gradle unitTest jacocoTestReport

Resources