UNOMI-565 : add code coverage report (#411)
* add jacoco report
* improve folder detection
* improve sources resolution
* make it work offline
* update profile name
diff --git a/.github/workflows/unomi-ci-build-tests.yml b/.github/workflows/unomi-ci-build-tests.yml
index cb5f824..bba86b1 100644
--- a/.github/workflows/unomi-ci-build-tests.yml
+++ b/.github/workflows/unomi-ci-build-tests.yml
@@ -14,6 +14,7 @@
name: Execute unit tests
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
java: [ 1.8, 11]
steps:
@@ -30,6 +31,7 @@
name: Execute integration tests
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
java: [ 1.8, 11]
steps:
@@ -41,11 +43,16 @@
cache: maven
- name: Integration tests
run: mvn -ntp clean install -Pintegration-tests
+ - name: Archive code coverage logs
+ uses: actions/upload-artifact@v3
+ with:
+ name: unomi-code-coverage-jdk${{ matrix.java }}-${{ github.run_number }}
+ path: itests/target/site/jacoco
- name: Archive unomi logs
uses: actions/upload-artifact@v3
if: failure()
with:
- name: unomi-${{ matrix.java }}-${{ github.run_number }}
+ name: unomi-log-jdk${{ matrix.java }}-${{ github.run_number }}
path: itests/target/exam/**/data/log
- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
diff --git a/.gitignore b/.gitignore
index 3aef7a6..1d2e17a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,4 +14,5 @@
allCountries.zip
rest/.miredot-offline.json
/extensions/salesforce-connector/test.properties
-**/*.versionsBackup
\ No newline at end of file
+**/*.versionsBackup
+itests/src/main
\ No newline at end of file
diff --git a/itests/jacoco-report.sh b/itests/jacoco-report.sh
new file mode 100755
index 0000000..b4ff826
--- /dev/null
+++ b/itests/jacoco-report.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+################################################################################
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+################################################################################
+echo "Copy sources and classes locally"
+for project in $(echo ../*/); do
+ echo " get sources for $project"
+ if [[ -d ${project}target ]]; then
+ echo " sources and target found for $project"
+ cp -rf ${project}src/main src
+ cp -rf ${project}target/classes target
+ for subproject in $(echo ${project}*/); do
+ echo " get sources for sub $subproject"
+ if [[ -d ${subproject}target/classes ]]; then
+ echo " sources and target found for $subproject"
+ cp -rf ${subproject}src/main src
+ cp -rf ${subproject}target/classes target
+ fi
+ for subsubproject in $(echo ${subproject}*/); do
+ echo " get sources for sub $subsubproject"
+ if [[ -d ${subsubproject}target/classes ]]; then
+ echo " sources and target found for $subsubproject"
+ cp -rf ${subsubproject}src/main src
+ cp -rf ${subsubproject}target/classes target
+ fi
+ done
+ done
+ fi
+done
+mvn jacoco:report -Dit.code.coverage=true
+echo "clean up src/main"
+rm -rf src/main
diff --git a/itests/pom.xml b/itests/pom.xml
index 86955ad..1de0f63 100644
--- a/itests/pom.xml
+++ b/itests/pom.xml
@@ -16,7 +16,8 @@
~ limitations under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.unomi</groupId>
@@ -151,6 +152,7 @@
</dependencies>
<profiles>
+
<profile>
<id>run-tests</id>
<activation>
@@ -158,6 +160,29 @@
</activation>
<build>
<plugins>
+ <plugin>
+ <groupId>com.googlecode.maven-download-plugin</groupId>
+ <artifactId>download-maven-plugin</artifactId>
+ <version>1.3.0</version>
+ <executions>
+ <execution>
+ <!-- the wget goal actually binds itself to this phase by default -->
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>wget</goal>
+ </goals>
+ <configuration>
+ <url>
+ https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.8/jacoco-0.8.8.zip
+ </url>
+ <outputFileName>jacoco.zip</outputFileName>
+ <unpack>true</unpack>
+ <outputDirectory>${project.build.directory}/jacoco/</outputDirectory>
+ <failOnError>false</failOnError>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<!-- Needed if you use versionAsInProject() -->
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
@@ -188,7 +213,8 @@
</environmentVariables>
<instanceSettings>
<properties>
- <cluster.routing.allocation.disk.threshold_enabled>false</cluster.routing.allocation.disk.threshold_enabled>
+ <cluster.routing.allocation.disk.threshold_enabled>false
+ </cluster.routing.allocation.disk.threshold_enabled>
<http.cors.allow-origin>*</http.cors.allow-origin>
</properties>
</instanceSettings>
@@ -238,6 +264,49 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <artifactId>exec-maven-plugin</artifactId>
+ <groupId>org.codehaus.mojo</groupId>
+ <executions>
+ <execution>
+ <id>Generate code coverage report</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>${basedir}/jacoco-report.sh</executable>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>itest-code-coverage</id>
+ <activation>
+ <property>
+ <name>it.code.coverage</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.7.7.201606060606</version>
+ <executions>
+ <execution>
+ <phase>post-site</phase>
+ <id>report</id>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</profile>
diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index 1007ff7..9abf854 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -73,6 +73,9 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -125,7 +128,8 @@
@Inject
protected BundleContext bundleContext;
- @Inject @Filter(timeout = 600000)
+ @Inject
+ @Filter(timeout = 600000)
protected BundleWatcher bundleWatcher;
@Inject
@@ -150,7 +154,7 @@
}
- protected void removeItems(final Class<? extends Item> ...classes) throws InterruptedException {
+ protected void removeItems(final Class<? extends Item>... classes) throws InterruptedException {
Condition condition = new Condition(definitionsService.getConditionType("matchAllCondition"));
for (Class<? extends Item> aClass : classes) {
persistenceService.removeByQuery(condition, aClass);
@@ -257,6 +261,17 @@
options.add(0, debugConfiguration(port, hold));
}
+ // Jacoco setup
+ final String agentFile = System.getProperty("user.dir") + "/target/jacoco/lib/jacocoagent.jar";
+ Path path = Paths.get(agentFile);
+ if (Files.exists(path)) {
+ final String jacocoOption = "-javaagent:" + agentFile + "=destfile=" + System.getProperty("user.dir") + "/target/jacoco.exec,includes=org.apache.unomi.*";
+ LOGGER.info("set jacoco java agent: {}", jacocoOption);
+ options.add(new VMOption(jacocoOption));
+ } else {
+ LOGGER.warn("Unable to set jacoco agent as {} was not found", agentFile);
+ }
+
if (JavaVersionUtil.getMajorVersion() >= 9) {
Option[] jdk9PlusOptions = new Option[]{
new VMOption("--add-reads=java.xml=java.logging"),
@@ -338,10 +353,10 @@
}
}
- protected String getValidatedBundleJSON(final String resourcePath, Map<String,String> parameters) throws IOException {
+ protected String getValidatedBundleJSON(final String resourcePath, Map<String, String> parameters) throws IOException {
String jsonString = bundleResourceAsString(resourcePath);
if (parameters != null && parameters.size() > 0) {
- for (Map.Entry<String,String> parameterEntry : parameters.entrySet()) {
+ for (Map.Entry<String, String> parameterEntry : parameters.entrySet()) {
jsonString = jsonString.replace("###" + parameterEntry.getKey() + "###", parameterEntry.getValue());
}
}
@@ -378,7 +393,7 @@
ServiceListener serviceListener = e -> {
LOGGER.info("Service {} {}", e.getServiceReference().getProperty("objectClass"), serviceEventTypeToString(e));
if ((e.getType() == ServiceEvent.UNREGISTERING || e.getType() == ServiceEvent.REGISTERED)
- && ((String[])e.getServiceReference().getProperty("objectClass"))[0].equals(serviceName)) {
+ && ((String[]) e.getServiceReference().getProperty("objectClass"))[0].equals(serviceName)) {
latch1.countDown();
}
};
@@ -469,7 +484,7 @@
}
protected CloseableHttpResponse post(final String url, final String resource) {
- return post(url,resource, JSON_CONTENT_TYPE);
+ return post(url, resource, JSON_CONTENT_TYPE);
}
protected CloseableHttpResponse delete(final String url) {
@@ -588,6 +603,7 @@
void registerEventType(String jsonSchemaFileName) {
post(JSONSCHEMA_URL, "schemas/events/" + jsonSchemaFileName, ContentType.TEXT_PLAIN);
}
+
void unRegisterEventType(String jsonSchemaId) {
delete(JSONSCHEMA_URL + "/" + Base64.getEncoder().encodeToString(jsonSchemaId.getBytes()));
}