SonarCloud incorrectly reporting lines as uncovered

  • ALM used: Github
  • CI system used: Github Actions
  • Scanner command used:
sonar-scanner 
   -Dsonar.projectVersion=1.35.13
   -Dsonar.branch.name=feature/abc 
   -Dsonar.cfamily.gcov.reportsPath=.builddir/.builddir-test-unit-coverage/ 
   -Dsonar.cfamily.compile-commands=.builddir/.builddir-test-unit-coverage/compile_commands.json
   -X 

Here is the essence of the PR I’m dealing with - a diff of 2 lines:

These lines are covered in unit-tests by calling constructor with a wide range of various parameters.

The fact that diff lines are covered by unit tests is confirmed by HTML report generated using fastcov:

Yet when I navigate to the PR page in SonarCloud I see the following:
image

SonarCloud seems to detect the changed lines but does not detect their coverage.

Here is the summary of the logs:

08:05:38.876 INFO: SonarScanner 5.0.1.3006
08:05:38.876 INFO: Java 17.0.7 Eclipse Adoptium (64-bit)
08:05:38.876 INFO: Linux 6.8.0-76060800daily20240311-generic amd64
...
10:40:26.311 DEBUG: /app/src/libname/network/dns/resolvers/dns_record.hpp not marked as unchanged: file content changed
...
10:40:34.908 INFO: Parsing /app/.builddir/.builddir-test-unit-coverage/libname/CMakeFiles/libname.dir/network/dns/resolvers/dns_record.hpp.gcov
...
10:40:39.297 INFO: Sensor gcov [cpp] (done) | time=10009ms
10:40:39.297 INFO: Sensor Zero Coverage Sensor
10:40:39.337 INFO: Sensor Zero Coverage Sensor (done) | time=40ms
10:40:39.344 INFO: SCM Publisher SCM provider for this project is: git
10:40:39.345 INFO: SCM Publisher 3 source files to be analyzed
10:40:39.348 DEBUG: Collecting committed files
10:40:39.375 DEBUG: Collecting committed files (done) | time=27ms
10:40:39.375 DEBUG: Using GIT_NATIVE_BLAME strategy to blame files
10:40:39.381 DEBUG: Failed to find git native client
java.io.IOException: Cannot run program "git": error=2, No such file or directory
        at java.base/java.lang.ProcessBuilder.start(Unknown Source)
        at java.base/java.lang.ProcessBuilder.start(Unknown Source)
        at org.sonar.scm.git.ProcessWrapperFactory$ProcessWrapper.execute(ProcessWrapperFactory.java:50)
        at org.sonar.scm.git.GitBlameCommand.checkIfEnabled(GitBlameCommand.java:66)
        at org.sonar.scm.git.CompositeBlameCommand.blameWithNativeGitCommand(CompositeBlameCommand.java:107)
        at org.sonar.scm.git.CompositeBlameCommand.blame(CompositeBlameCommand.java:86)
        at org.sonar.scanner.scm.ScmPublisher.publish(ScmPublisher.java:76)
        at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:164)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
        at org.sonar.scanner.bootstrap.ScannerContainer.doAfterStart(ScannerContainer.java:399)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
        at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:131)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
        at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:60)
        at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:54)
        at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.base/java.lang.reflect.Method.invoke(Unknown Source)
        at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
        at jdk.proxy1/jdk.proxy1.$Proxy0.execute(Unknown Source)
        at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189)
        at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:126)
        at org.sonarsource.scanner.cli.Main.execute(Main.java:81)
        at org.sonarsource.scanner.cli.Main.main(Main.java:62)
Caused by: java.io.IOException: error=2, No such file or directory
        at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
        at java.base/java.lang.ProcessImpl.<init>(Unknown Source)
        at java.base/java.lang.ProcessImpl.start(Unknown Source)
        ... 30 common frames omitted

10:40:39.383 DEBUG: Blame file (JGit) src/libname/network/dns/resolvers/dns_record.hpp
10:40:39.383 DEBUG: Blame file (JGit) src/test/network/dns/resolver/dns_record_test.cpp
10:40:39.383 DEBUG: Blame file (JGit) src/test/network/dns/resolver/record_resolver_test.cpp
10:40:39.613 INFO: SCM Publisher 3/3 source files have been analyzed (done) | time=267ms

Any ideas why SonarCloud might not be detecting the coverage for the changed lines in dns_record.hpp?

1 Like

Hey there.

Can you provide the content of this file?

Parsing /app/.builddir/.builddir-test-unit-coverage/libname/CMakeFiles/libname.dir/network/dns/resolvers/dns_record.hpp.gcov

@Colin thanks for the pointer - your question led me to the root of the problem:

if I only run the unit-test dns_record_test.cpp, then execute:

find .builddir/.builddir-test-unit-coverage/libname -name '*.o' -execdir gcov '{}' ';'

then dns_record.hpp.gcov indeed does not show coverage for the lines in question.

My guess is that something is wrong with the above approach of generating gcov files from unit test outputs that does not occur when we use fastcov. It does not seem like a SonarCloud issue specifically, but if you have any recommendations for a reliable way to generate gcov files for SonarScanner to consume I’ll gladly hear those out.

I don’t have much to say on the topic other than to point to our docs on C/C++ Test Coverage. SonarQube only consumes the reports, it doesn’t care so much about how they’re made.