General Discussions
Welcome to the second part of the Testing posts serie!
As promised, this post will cover the integration of our previous testing setup into a Gitlab CI. We'll see how to:
• Prepare a specific Runner to ease the run and keep our CI file to a minimum.
• Prepare the CI file to build our project, run the analysis and prepare the result.
• Access the results on GitLab
Preparing the runner
To have the least amount of work to do in the gitalb-ci.yml, we prepare a runner equipped with the necessary tools. Here is it's dockerfile:
FROM gcc:latest
ARG SONAR_SCANNER_VERSION="7.0.2.4839"
ARG SONAR_SERVER_URL="https://next.sonarqube.com/sonarqube"
ARG UNITY_RELEASE="2.6.1"
ARG UNITY_RELEASE_URL="https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v${UNITY_RELEASE}.zip"
RUN apt update && apt install -y curl git gcovr cmake
RUN curl -sSLo sonar-scanner.zip "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux-x64.zip" \
&& unzip -o sonar-scanner.zip \
&& mv sonar-scanner-${SONAR_SCANNER_VERSION}-linux-x64 sonar-scanner \
&& rm sonar-scanner.zip
RUN curl -sSLo build-wrapper.zip "${SONAR_SERVER_URL}/static/cpp/build-wrapper-linux-x86.zip" \
&& unzip -o build-wrapper.zip \
&& mv build-wrapper-linux-x86 build-wrapper \
&& rm build-wrapper.zip
RUN curl -sSLo Unity.zip "${UNITY_RELEASE_URL}" \
&& unzip -o Unity.zip \
&& cd Unity-${UNITY_RELEASE} \
&& cmake -B build \
&& cmake --build build \
&& cmake --install build
ENV PATH="/build-wrapper:/sonar-scanner/bin:${PATH}"
It will get both sonar-scanner and build-wrapper binaries and add them to the PATH environment variable, letting us access them easily in the next step.
Registering the runner can be done following the official documentation, as it is not the focus of this post. It is just to remember to tag the runner with a tag which will be used afterward (i.e.: testing, sonar, ...). The next step will need a runner with the sonar-testing tag.
Preparing the CI file
The CI file will do the following:
• Build our code and store the output as artifact.
• Run the analysis using sonar-scanner.
Here is the CI file:
variables:
SONAR_SERVER_URL: https://next.sonarqube.com/sonarqube # Replace with your SonarQube server URL
SONAR_SCANNER_VERSION: 7.0.2.4839 # Find the latest version in the "Linux" link on this page:
# https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/
BUILD_WRAPPER_OUT_DIR: bw-output # Directory where build-wrapper output will be placed
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
# note that SONAR_TOKEN is transmitted to the environment through Gitlab CI
UNITY_RELEASE_URL: https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.6.1.zip
build:
stage: deploy
tags:
- sonar-testing
script:
- echo "Building the application"
- cd app
- cmake -B build
- build-wrapper-linux-x86-64 --out-dir "${BUILD_WRAPPER_OUT_DIR}" cmake --build build/ --config Release
artifacts:
paths:
- app/build/app
untracked: false
when: on_success
access: all
cache:
policy: push
key: "${CI_COMMIT_SHORT_SHA}"
paths:
- app/${BUILD_WRAPPER_OUT_DIR}
- app/build/
unity-tests:
stage: .post
tags:
- sonar-testing
script:
- echo "Running Unity unit tests"
- cd app
- ctest --test-dir build --output-junit junit.xml
- gcovr -e main.c --sonarqube > coverage.xml
artifacts:
untracked: false
when: always
paths:
- app/build/junit.xml
- app/coverage.xml
reports:
junit: app/build/junit.xml
cache:
policy: pull-push
key: "${CI_COMMIT_SHORT_SHA}"
paths:
- app/build/
- app/coverage.xml
- app/${BUILD_WRAPPER_OUT_DIR}
sonar-qube:
stage: .post
tags:
- sonar-testing
needs:
- job: unity-tests
artifacts: true
script:
- cd app
- sonar-scanner
cache:
policy: pull
key: "${CI_COMMIT_SHORT_SHA}"
paths:
- app/${BUILD_WRAPPER_OUT_DIR}
- app/coverage.xml
It is split in three jobs:
• Building the project and getting the build wrapper output
• Running the Unity tests
• Running the sonar-scanner analysis and sending it to the sonar-cloud server
Each of these job ask to use a runner having the sonar-testing tag, which will use the runner previously configured.
Accessing the results
Once you push on main, the CI will run and execute all the jobs. After a successful run, the results can be accessed on GitLab.
Here is the successful pipeline:
All jobs passed!
And here is the testing results, available on Gitlab:
We see that all the tests ran and no error was reported
Conclusion
This mini-serie showed the integration of only a subset of the possible frameworks available. This solution offer easy to use and setup components, already validated and widely adopted in the testing world. It shows the first steps on how to build a robust and automated test environment, which also offering rich and useful inside about your code, thanks to the Sonar-Scanner analysis.
I hope this will encourage you to try this kind of setup in your projects and that you'll build nice and bug-free code a bit more easily next time!