From de31eed9b439012fbc853bb7864f1b6e19c8bd18 Mon Sep 17 00:00:00 2001
From: Lars Johansson <lars.johansson@ess.eu>
Date: Wed, 27 Sep 2023 15:20:21 +0200
Subject: [PATCH] Add code coverage for integration tests with Docker

---
 Dockerfile.integrationtest                    | 13 ++++
 docker-compose-integrationtest.yml            |  6 +-
 pom.xml                                       | 66 +++++++++++++++++++
 .../openepics/names/docker/HealthcheckIT.java | 27 +++++++-
 .../org/openepics/names/docker/ITUtil.java    |  8 ++-
 .../org/openepics/names/docker/NamesIT.java   | 24 ++++++-
 .../org/openepics/names/docker/ReportIT.java  | 25 ++++++-
 .../names/docker/StructuresDeviceGroupIT.java | 25 ++++++-
 .../names/docker/StructuresDeviceTypeIT.java  | 25 ++++++-
 .../names/docker/StructuresDisciplineIT.java  | 25 ++++++-
 .../names/docker/StructuresSubsystemIT.java   | 25 ++++++-
 .../names/docker/StructuresSystemGroupIT.java | 25 ++++++-
 .../names/docker/StructuresSystemIT.java      | 25 ++++++-
 .../docker/complex/NamesInstanceIndexIT.java  | 26 +++++++-
 .../names/docker/complex/NamesLegacyIT.java   | 25 ++++++-
 .../NamesLegacyStructuresDeleteIT.java        | 25 ++++++-
 .../NamesLegacyStructuresUpdateIT.java        | 25 ++++++-
 .../names/docker/complex/NamesMultipleIT.java | 25 ++++++-
 .../docker/complex/StructuresLevel3IT.java    | 25 ++++++-
 .../docker/complex/StructuresMultipleIT.java  | 25 ++++++-
 .../resources/INTEGRATIONTEST_DOCKER_RUN.md   | 25 ++++++-
 21 files changed, 497 insertions(+), 23 deletions(-)
 create mode 100644 Dockerfile.integrationtest

diff --git a/Dockerfile.integrationtest b/Dockerfile.integrationtest
new file mode 100644
index 00000000..273fc766
--- /dev/null
+++ b/Dockerfile.integrationtest
@@ -0,0 +1,13 @@
+# ------------------------------------------------------------------------------
+# Copyright (C) 2021 European Spallation Source ERIC.
+# ------------------------------------------------------------------------------
+
+FROM openjdk:17
+
+# deployment unit
+COPY target/naming-backend-*.jar /naming/naming-backend.jar
+
+# code coverage
+COPY target/jacoco/jacocoagent.jar /naming/jacocoagent.jar
+
+CMD ["java", "-jar", "/naming/naming-backend.jar", "--spring.config.name=application"]
diff --git a/docker-compose-integrationtest.yml b/docker-compose-integrationtest.yml
index b7801292..b84cd633 100644
--- a/docker-compose-integrationtest.yml
+++ b/docker-compose-integrationtest.yml
@@ -5,7 +5,9 @@
 version: '3.7'
 services:
   naming:
-    build: ./
+    build:
+      context: .
+      dockerfile: Dockerfile.integrationtest
     networks:
       - naming-net
     ports:
@@ -13,7 +15,7 @@ services:
     depends_on:
       postgres: 
         condition: service_healthy
-    command: "java -jar /naming/naming-backend.jar"
+    command: "java -javaagent:/naming/jacocoagent.jar=destfile=/naming/jacoco.exec,output=file,append=false -jar /naming/naming-backend.jar"
   
   postgres:
     image: "postgres:9.6.7"
diff --git a/pom.xml b/pom.xml
index 54c5aa76..26555465 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,12 @@
       <artifactId>postgresql</artifactId>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.jacoco</groupId>
+      <artifactId>org.jacoco.agent</artifactId>
+      <version>0.8.10</version>
+      <scope>runtime</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.springframework.boot</groupId>
@@ -137,6 +143,66 @@
           <skipITs>${skipITs}</skipITs>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.jacoco</groupId>
+                  <artifactId>org.jacoco.agent</artifactId>
+                  <classifier>runtime</classifier>
+                  <outputDirectory>${project.build.directory}/jacoco</outputDirectory>
+                  <destFileName>jacocoagent.jar</destFileName>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>0.8.10</version>
+        <executions>
+          <execution>
+            <id>merge</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>merge</goal>
+            </goals>
+            <configuration>
+              <fileSets>
+                <fileSet>
+                  <directory>${project.build.directory}</directory>
+                  <includes>
+                    <include>jacoco*.exec</include>
+                  </includes>
+                </fileSet>
+              </fileSets>
+              <destFile>${project.build.directory}/site/jacoco/jacoco.exec</destFile>
+            </configuration>
+          </execution>
+          <execution>
+            <id>report</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+            <configuration>
+              <dataFile>${project.build.directory}/site/jacoco/jacoco.exec</dataFile>
+              <outputDirectory>${project.build.directory}/site/jacoco</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/src/test/java/org/openepics/names/docker/HealthcheckIT.java b/src/test/java/org/openepics/names/docker/HealthcheckIT.java
index 09ca51b8..4c61926e 100644
--- a/src/test/java/org/openepics/names/docker/HealthcheckIT.java
+++ b/src/test/java/org/openepics/names/docker/HealthcheckIT.java
@@ -24,19 +24,24 @@ import static org.junit.jupiter.api.Assertions.fail;
 import java.io.File;
 import java.io.IOException;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
- * Purpose of this class is to test healthcheck endpoint.
+ * Purpose of this class is to test healthcheck endpoints.
  * In practice, it means means to have Naming and PostgreSQL up and running.
  * </p>
  *
@@ -50,6 +55,24 @@ class HealthcheckIT {
         new DockerComposeContainer<>(new File("docker-compose-integrationtest.yml"))
             .waitingFor(ITUtil.NAMING, Wait.forLogMessage(".*Started NamingApplication.*", 1));
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + HealthcheckIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void readHealthcheck() {
         try {
diff --git a/src/test/java/org/openepics/names/docker/ITUtil.java b/src/test/java/org/openepics/names/docker/ITUtil.java
index 315f9d9e..25fcdd23 100644
--- a/src/test/java/org/openepics/names/docker/ITUtil.java
+++ b/src/test/java/org/openepics/names/docker/ITUtil.java
@@ -54,7 +54,7 @@ public class ITUtil {
     static final String HTTP          = "http://";
     static final String HEADER_JSON   = "'Content-Type: application/json'";
 
-    static final String IP_PORT_NAMING = "127.0.0.1:8080";
+    static final String IP_PORT_NAMING    = "127.0.0.1:8080";
 
     static final String API_V1_HISTORY    = "/api/v1/history";
     static final String API_V1_NAMES      = "/api/v1/names";
@@ -78,6 +78,12 @@ public class ITUtil {
     private static final String CURLY_BRACE_END   = "}";
     private static final String HTTP_REPLY        = "HTTP";
 
+    // code coverage
+
+    public static final String JACOCO_EXEC_PATH     = "/naming/jacoco.exec";
+    public static final String JACOCO_TARGET_PREFIX = "target/jacoco_";
+    public static final String JACOCO_TARGET_SUFFIX = ".exec";
+
     /**
      * This class is not to be instantiated.
      */
diff --git a/src/test/java/org/openepics/names/docker/NamesIT.java b/src/test/java/org/openepics/names/docker/NamesIT.java
index 509dabd2..3835c001 100644
--- a/src/test/java/org/openepics/names/docker/NamesIT.java
+++ b/src/test/java/org/openepics/names/docker/NamesIT.java
@@ -25,8 +25,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 import java.io.File;
 import java.io.IOException;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
@@ -41,16 +43,18 @@ import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.rest.beans.response.ResponsePageNameElements;
 import org.openepics.names.util.NameCommand;
 import org.openepics.names.util.NameElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.dockerjava.api.DockerClient;
 
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test names endpoints.
@@ -169,6 +173,24 @@ class NamesIT {
         deviceTypeTT = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + NamesIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceName() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/ReportIT.java b/src/test/java/org/openepics/names/docker/ReportIT.java
index 53e0b27c..735e60b5 100644
--- a/src/test/java/org/openepics/names/docker/ReportIT.java
+++ b/src/test/java/org/openepics/names/docker/ReportIT.java
@@ -24,16 +24,21 @@ import static org.junit.jupiter.api.Assertions.fail;
 import java.io.File;
 import java.io.IOException;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test report endpoints.
@@ -49,6 +54,24 @@ class ReportIT {
         new DockerComposeContainer<>(new File("docker-compose-integrationtest.yml"))
             .waitingFor(ITUtil.NAMING, Wait.forLogMessage(".*Started NamingApplication.*", 1));
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + ReportIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void readReportAbout() {
         try {
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
index 86fbba77..f36928ba 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
@@ -24,8 +24,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and device group.
@@ -117,6 +122,24 @@ class StructuresDeviceGroupIT {
         discipline2Uuid = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresDeviceGroupIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
index 7fab4faa..5fb65b4d 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
@@ -24,8 +24,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and device type.
@@ -117,6 +122,24 @@ class StructuresDeviceTypeIT {
         deviceGroupUuid = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresDeviceTypeIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
index 15d0bbf7..91b917ae 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
@@ -24,8 +24,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
 import org.openepics.names.rest.beans.element.StructureElement;
@@ -36,14 +38,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and discipline.
@@ -91,6 +96,24 @@ class StructuresDisciplineIT {
         new DockerComposeContainer<>(new File("docker-compose-integrationtest.yml"))
             .waitingFor(ITUtil.NAMING, Wait.forLogMessage(".*Started NamingApplication.*", 1));
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresDisciplineIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
index ff4d4cd5..d3f92308 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
@@ -24,8 +24,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and subsystem.
@@ -117,6 +122,24 @@ class StructuresSubsystemIT {
         systemUuid = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresSubsystemIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
index 8c0f4836..cc81eb88 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
@@ -25,8 +25,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
 import org.openepics.names.rest.beans.element.StructureElement;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and system group.
@@ -90,6 +95,24 @@ class StructuresSystemGroupIT {
         new DockerComposeContainer<>(new File("docker-compose-integrationtest.yml"))
             .waitingFor(ITUtil.NAMING, Wait.forLogMessage(".*Started NamingApplication.*", 1));
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresSystemGroupIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
index 0a8134c3..55ab21b7 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
@@ -24,8 +24,10 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
 import java.net.HttpURLConnection;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.rest.beans.Type;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints and system.
@@ -109,6 +114,24 @@ class StructuresSystemIT {
         systemGroupUuid = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + StructuresSystemIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void equivalenceMnemonic() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/NamesInstanceIndexIT.java b/src/test/java/org/openepics/names/docker/complex/NamesInstanceIndexIT.java
index f59ccf32..b26279e4 100644
--- a/src/test/java/org/openepics/names/docker/complex/NamesInstanceIndexIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/NamesInstanceIndexIT.java
@@ -19,8 +19,11 @@
 package org.openepics.names.docker.complex;
 
 import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -34,14 +37,17 @@ import org.openepics.names.rest.beans.element.StructureElement;
 import org.openepics.names.rest.beans.element.StructureElementCommand;
 import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.util.NameCommand;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test names endpoints and rules for disciplines P&ID and Scientific in particular.
@@ -537,6 +543,24 @@ class NamesInstanceIndexIT {
         deviceType_BMD_TT = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + NamesInstanceIndexIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
   @Test
   void checkCreateInstanceIndex_Cryo() {
       // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/NamesLegacyIT.java b/src/test/java/org/openepics/names/docker/complex/NamesLegacyIT.java
index 037e4243..21f72def 100644
--- a/src/test/java/org/openepics/names/docker/complex/NamesLegacyIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/NamesLegacyIT.java
@@ -21,8 +21,10 @@ package org.openepics.names.docker.complex;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -35,14 +37,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandConfirm;
 import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test rules for legacy name.
@@ -399,6 +404,24 @@ class NamesLegacyIT {
         //         Sys23-Sub233:Di2-Dt233-233
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + NamesLegacyIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void legacyNameSystemStructure() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresDeleteIT.java b/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresDeleteIT.java
index 950ae7c5..4522e1e1 100644
--- a/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresDeleteIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresDeleteIT.java
@@ -19,8 +19,10 @@
 package org.openepics.names.docker.complex;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -33,14 +35,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandConfirm;
 import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test rules for legacy name.
@@ -435,6 +440,24 @@ class NamesLegacyStructuresDeleteIT {
         ITUtilNames.assertExists("Sys23-Sub233:Di2-Dt233-233", Boolean.TRUE);
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + NamesLegacyStructuresDeleteIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void deleteSystemStructure() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresUpdateIT.java b/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresUpdateIT.java
index 7a58a243..90ce56b4 100644
--- a/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresUpdateIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/NamesLegacyStructuresUpdateIT.java
@@ -19,8 +19,10 @@
 package org.openepics.names.docker.complex;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -33,14 +35,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test rules for legacy name.
@@ -436,6 +441,24 @@ class NamesLegacyStructuresUpdateIT {
         ITUtilNames.assertExists("Sys23-Sub233:Di2-Dt233-233", Boolean.TRUE);
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH , ITUtil.JACOCO_TARGET_PREFIX + NamesLegacyStructuresUpdateIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void updateSystemStructure() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/NamesMultipleIT.java b/src/test/java/org/openepics/names/docker/complex/NamesMultipleIT.java
index 9036727c..d407ee37 100644
--- a/src/test/java/org/openepics/names/docker/complex/NamesMultipleIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/NamesMultipleIT.java
@@ -23,8 +23,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -40,14 +42,17 @@ import org.openepics.names.rest.beans.element.StructureElement;
 import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.util.NameCommand;
 import org.openepics.names.util.NameElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test names endpoints.
@@ -130,6 +135,24 @@ class NamesMultipleIT {
         deviceType_Cryo_FS = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH, ITUtil.JACOCO_TARGET_PREFIX + NamesMultipleIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void checkCreate() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/StructuresLevel3IT.java b/src/test/java/org/openepics/names/docker/complex/StructuresLevel3IT.java
index d395e95b..8c2d1ae8 100644
--- a/src/test/java/org/openepics/names/docker/complex/StructuresLevel3IT.java
+++ b/src/test/java/org/openepics/names/docker/complex/StructuresLevel3IT.java
@@ -22,8 +22,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -32,14 +34,17 @@ import org.openepics.names.rest.beans.Type;
 import org.openepics.names.rest.beans.element.StructureElement;
 import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints.
@@ -266,6 +271,24 @@ class StructuresLevel3IT {
         deviceGroupBMD = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH, ITUtil.JACOCO_TARGET_PREFIX + StructuresLevel3IT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void createSubsystem() {
         // purpose
diff --git a/src/test/java/org/openepics/names/docker/complex/StructuresMultipleIT.java b/src/test/java/org/openepics/names/docker/complex/StructuresMultipleIT.java
index 7576f787..a353e820 100644
--- a/src/test/java/org/openepics/names/docker/complex/StructuresMultipleIT.java
+++ b/src/test/java/org/openepics/names/docker/complex/StructuresMultipleIT.java
@@ -23,8 +23,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.File;
+import java.util.Optional;
 import java.util.UUID;
 
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.openepics.names.docker.ITUtil;
@@ -37,14 +39,17 @@ import org.openepics.names.rest.beans.element.StructureElementCommandCreate;
 import org.openepics.names.rest.beans.element.StructureElementCommandUpdate;
 import org.openepics.names.util.StructureCommand;
 import org.openepics.names.util.StructureElementUtil;
+import org.testcontainers.containers.ContainerState;
 import org.testcontainers.containers.DockerComposeContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import com.github.dockerjava.api.DockerClient;
+
 /**
  * Integration tests for Naming and PostgreSQL that make use of existing dockerization
- * with docker-compose.yml / Dockerfile.
+ * with docker-compose-integrationtest.yml / Dockerfile.integrationtest.
  *
  * <p>
  * Purpose of this class is to test structures endpoints.
@@ -120,6 +125,24 @@ class StructuresMultipleIT {
         deviceTypeUuid = approvedStructureElement.getUuid();
     }
 
+    @AfterAll
+    public static void extractJacocoReport() {
+        // extract jacoco report from container file system
+        //     stop jvm to make data available
+
+        Optional<ContainerState> container = ENVIRONMENT.getContainerByServiceName(ITUtil.NAMING);
+        if (container.isPresent()) {
+            ContainerState cs = container.get();
+            DockerClient dc = cs.getDockerClient();
+            dc.stopContainerCmd(cs.getContainerId()).exec();
+            try {
+                cs.copyFileFromContainer(ITUtil.JACOCO_EXEC_PATH, ITUtil.JACOCO_TARGET_PREFIX + StructuresMultipleIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX);
+            } catch (Exception e) {
+                // proceed if file cannot be copied
+            }
+        }
+    }
+
     @Test
     void checkCreate() {
         // purpose
diff --git a/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md b/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md
index c19b8045..a3a1ac80 100644
--- a/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md
+++ b/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md
@@ -21,15 +21,16 @@ All or individual integration tests (including methods) can be run in IDE as JUn
 
 ##### Maven
 
-All integration tests can be run via Maven.
+To run all integration tests via Maven.
 
 ```
 mvn failsafe:integration-test -DskipITs=false
 ```
 
-Individual integration tests (classes) can also be run via Maven.
+To run individual integration tests (classes) via Maven.
 
 ```
+mvn test -Dtest=org.openepics.names.docker.HealthcheckIT
 mvn test -Dtest=org.openepics.names.docker.NamesIT
 mvn test -Dtest=org.openepics.names.docker.ReportIT
 mvn test -Dtest=org.openepics.names.docker.DeviceGroupIT
@@ -47,6 +48,23 @@ mvn test -Dtest=org.openepics.names.docker.complex.StructuresLevel3IT
 mvn test -Dtest=org.openepics.names.docker.complex.StructuresMultipleIT
 ```
 
+##### Code coverage
+
+After integration tests have been run, run below command to process coverage data. This applies for all and individual integration tests (including methods).
+
+```
+mvn verify
+```
+
+Result is available in `target/site/jacoco` folder and includes code coverage execution data and reports.
+
+```
+index.html
+jacoco.exec
+jacoco.csv
+jacoco.xml
+```
+
 ### Note
 
 ##### Build
@@ -64,4 +82,5 @@ mvn test -Dtest=org.openepics.names.docker.complex.StructuresMultipleIT
 
 ##### Performance
 
-* It may take a minute to run a test. This includes time to set up the test environment, perform the test and tear down the test environment. Setting up the test environment takes most of that time.
+* It may take a minute to run an integration test. This includes time to set up the test environment, perform the test and tear down the test environment. Setting up the test environment takes most of that time.
+* It may take additional time to run an integration test with code coverage.
-- 
GitLab