diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml
index a64785635ee2171947000336bc099aae5a15d29c..114544101a3a50d8ccf0aa9c932271bf2988820b 100644
--- a/dbrepo-data-service/pom.xml
+++ b/dbrepo-data-service/pom.xml
@@ -40,8 +40,6 @@
         <opencsv.version>5.7.1</opencsv.version>
         <super-csv.version>2.4.0</super-csv.version>
         <jsql.version>4.6</jsql.version>
-        <c3p0.version>0.9.5.5</c3p0.version>
-        <c3p0-hibernate.version>6.2.2.Final</c3p0-hibernate.version>
         <springdoc-openapi.version>2.1.0</springdoc-openapi.version>
         <hsqldb.version>2.7.2</hsqldb.version>
         <testcontainers.version>1.18.3</testcontainers.version>
@@ -157,6 +155,22 @@
             <artifactId>amqp-client</artifactId>
             <version>${rabbit-amqp-client.version}</version>
         </dependency>
+        <!-- Monitoring -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <version>${micrometer.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-observation-test</artifactId>
+            <version>${micrometer.version}</version>
+            <scope>test</scope>
+        </dependency>
         <!-- Testing -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7991ce5a393039fa622b8686063bc2e95151638
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java
@@ -0,0 +1,74 @@
+package at.tuwien.listener;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.config.MariaDbConfig;
+import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.exception.DatabaseNotFoundException;
+import at.tuwien.service.DatabaseService;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.amqp.core.Message;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.system.CapturedOutput;
+import org.springframework.boot.test.system.OutputCaptureExtension;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.containers.MariaDBContainer;
+import org.testcontainers.containers.RabbitMQContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+
+import static at.tuwien.utils.RabbitMqUtils.buildMessage;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith({SpringExtension.class, OutputCaptureExtension.class})
+@Testcontainers
+@MockOpensearch
+public class DefaultListenerIntegrationTest extends BaseUnitTest {
+
+    @MockBean
+    private DatabaseService databaseService;
+
+    @Autowired
+    private DefaultListener defaultListener;
+
+    @Container
+    private static RabbitMQContainer rabbitContainer = new RabbitMQContainer("rabbitmq:3.10");
+
+    @Container
+    private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
+
+    @BeforeEach
+    public void beforeEach() throws SQLException {
+        /* metadata database */
+        TABLE_1.setColumns(TABLE_1_COLUMNS);
+        DATABASE_1.setTables(List.of(TABLE_1, TABLE_2, TABLE_3));
+        MariaDbConfig.dropAllDatabases(CONTAINER_1);
+        MariaDbConfig.createInitDatabase(CONTAINER_1, DATABASE_1);
+    }
+
+    @Test
+    public void onMessage_succeeds(CapturedOutput output) throws DatabaseNotFoundException {
+        final Message request = buildMessage("dbrepo." + DATABASE_1_INTERNALNAME + "." + TABLE_1_INTERNALNAME, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>());
+
+        /* mock */
+        when(databaseService.findByInternalName(DATABASE_1_INTERNALNAME))
+                .thenReturn(DATABASE_1);
+
+        /* test */
+        defaultListener.onMessage(request);
+        assertTrue(output.getAll().contains("successfully inserted tuple"));
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
index 04aff250f5580a9ac1c68e68630acbc4eeca1f56..a366513a6840cc6e1713ab1deb2f2e23b98467b1 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java
@@ -1,14 +1,14 @@
 package at.tuwien.listener;
 
 import at.tuwien.BaseUnitTest;
-import at.tuwien.annotations.MockAmqp;
 import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.config.MariaDbConfig;
 import at.tuwien.config.MariaDbContainerConfig;
 import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.amqp.core.Message;
-import org.springframework.amqp.core.MessageProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.system.CapturedOutput;
@@ -19,10 +19,10 @@ import org.testcontainers.containers.RabbitMQContainer;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
-import java.nio.charset.StandardCharsets;
+import java.sql.SQLException;
 import java.util.HashMap;
-import java.util.Map;
 
+import static at.tuwien.utils.RabbitMqUtils.buildMessage;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @Log4j2
@@ -38,6 +38,16 @@ public class DefaultListenerUnitTest extends BaseUnitTest {
     @Container
     private static RabbitMQContainer rabbitContainer = new RabbitMQContainer("rabbitmq:3.10");
 
+    @Container
+    private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
+
+    @BeforeEach
+    public void beforeEach() throws SQLException {
+        /* metadata database */
+        MariaDbConfig.dropAllDatabases(CONTAINER_1);
+        MariaDbConfig.createInitDatabase(CONTAINER_1, DATABASE_1);
+    }
+
     @Test
     public void onMessage_routingKeyDatabaseAndTableMissing_fails(CapturedOutput output) {
         final Message request = buildMessage("dbrepo", "{}", new HashMap<>());
@@ -65,11 +75,13 @@ public class DefaultListenerUnitTest extends BaseUnitTest {
         assertTrue(output.getAll().contains("Failed to read object"));
     }
 
-    protected Message buildMessage(String routingKey, String payload, Map<String, Object> headers) {
-        final MessageProperties properties = new MessageProperties();
-        properties.setReceivedRoutingKey(routingKey);
-        properties.setHeaders(headers);
-        return new Message(payload.getBytes(StandardCharsets.UTF_8), properties);
+    @Test
+    public void onMessage_databaseNotFound_fails(CapturedOutput output) {
+        final Message request = buildMessage("dbrepo.database.table", "{\"id\":1}", new HashMap<>());
+
+        /* test */
+        defaultListener.onMessage(request);
+        assertTrue(output.getAll().contains("Failed to find database"));
     }
 
 }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..11d52c79efd91d66aec071b20d9b7f409d507dd0
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java
@@ -0,0 +1,50 @@
+package at.tuwien.mvc;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@AutoConfigureObservability
+@MockAmqp
+@MockOpensearch
+public class ActuatorEndpointMvcTest extends BaseUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Test
+    public void actuatorInfo_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/info"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void actuatorPrometheus_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/prometheus"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0781569eb8aff0e5aa91b1df6381dd10945f35c4
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java
@@ -0,0 +1,78 @@
+package at.tuwien.mvc;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.config.MetricsConfig;
+import at.tuwien.listener.DefaultListener;
+import io.micrometer.observation.tck.TestObservationRegistry;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.amqp.core.Message;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.HashMap;
+
+import static at.tuwien.utils.RabbitMqUtils.buildMessage;
+import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@Import(MetricsConfig.class)
+@AutoConfigureObservability
+@MockOpensearch
+public class PrometheusEndpointMvcTest extends BaseUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Autowired
+    private TestObservationRegistry registry;
+
+    @Autowired
+    private DefaultListener defaultListener;
+
+    @TestConfiguration
+    static class ObservationTestConfiguration {
+
+        @Bean
+        public TestObservationRegistry observationRegistry() {
+            return TestObservationRegistry.create();
+        }
+    }
+
+    @Test
+    public void prometheus_succeeds() throws Exception {
+
+        /* test */
+        this.mockMvc.perform(get("/actuator/prometheus"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void prometheusMessageReceiveExists_succeeds() {
+
+        /* mock */
+        defaultListener.onMessage(buildMessage("dbrepo.database", "{}", new HashMap<>()));
+
+        /* test */
+        assertThat(registry)
+                .hasObservationWithNameEqualTo("dbr_message_receive");
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SwaggerEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SwaggerEndpointMvcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c07446eee592ebdb8d2b7d7e631fdc9f10eca927
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SwaggerEndpointMvcTest.java
@@ -0,0 +1,37 @@
+package at.tuwien.mvc;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Log4j2
+@ExtendWith(SpringExtension.class)
+@AutoConfigureMockMvc
+@SpringBootTest
+@MockAmqp
+@MockOpensearch
+public class SwaggerEndpointMvcTest extends BaseUnitTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Test
+    public void swaggerUi_succeeds() throws Exception {
+        this.mockMvc.perform(get("/swagger-ui/index.html"))
+                .andDo(print())
+                .andExpect(status().isOk());
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..55feb01c14091d0d1f0dec7d1a492a7bf95adcca
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java
@@ -0,0 +1,103 @@
+package at.tuwien.service;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.user.User;
+import at.tuwien.exception.DatabaseNotFoundException;
+import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.repository.mdb.ContainerRepository;
+import at.tuwien.repository.mdb.DatabaseRepository;
+import at.tuwien.repository.mdb.ImageRepository;
+import at.tuwien.repository.mdb.UserRepository;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+@Testcontainers
+@MockAmqp
+@MockOpensearch
+public class DatabaseServiceIntegrationTest extends BaseUnitTest {
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private ImageRepository imageRepository;
+
+    @Autowired
+    private ContainerRepository containerRepository;
+
+    @Autowired
+    private DatabaseRepository databaseRepository;
+
+    @Autowired
+    private DatabaseService databaseService;
+
+    @BeforeEach
+    public void beforeEach() {
+        userRepository.save(USER_1);
+        imageRepository.save(IMAGE_1_SIMPLE);
+        containerRepository.save(CONTAINER_1_SIMPLE);
+        databaseRepository.save(DATABASE_1_SIMPLE);
+    }
+
+    @Test
+    public void find_succeeds() throws DatabaseNotFoundException {
+
+        /* test */
+        final Database response = databaseService.find(DATABASE_1_ID);
+        assertEquals(DATABASE_1_ID, response.getId());
+    }
+
+    @Test
+    public void find_fails() {
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            databaseService.find(DATABASE_2_ID);
+        });
+    }
+
+    @Test
+    public void findByInternalName_succeeds() throws DatabaseNotFoundException {
+
+        /* test */
+        final Database response = databaseService.findByInternalName(DATABASE_1_INTERNALNAME);
+        assertEquals(DATABASE_1_ID, response.getId());
+    }
+
+    @Test
+    public void findByInternalName_fails() {
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            databaseService.findByInternalName(DATABASE_2_INTERNALNAME);
+        });
+    }
+
+    @Test
+    public void findAll_succeeds() {
+
+        /* test */
+        final List<Database> response = databaseService.findAll();
+        assertEquals(1, response.size());
+        final Database database0 = response.get(0);
+        assertEquals(DATABASE_1_ID, database0.getId());
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
index 7fb17a5d3be2d49720feaabd804ad6a0cad2c229..669ae322bb7a1256fa4dfa9eeed4a073abe568d8 100644
--- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java
@@ -8,6 +8,7 @@ import at.tuwien.exception.DatabaseNotFoundException;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.repository.mdb.*;
+import at.tuwien.service.impl.QueueServiceImpl;
 import lombok.extern.log4j.Log4j2;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -16,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.testcontainers.containers.MariaDBContainer;
-import org.testcontainers.containers.RabbitMQContainer;
 import org.testcontainers.junit.jupiter.Container;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
@@ -26,6 +26,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Stream;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 @Log4j2
 @SpringBootTest
 @ExtendWith(SpringExtension.class)
@@ -52,7 +54,7 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
     private ImageRepository imageRepository;
 
     @Autowired
-    private QueueService queueService;
+    private QueueServiceImpl queueService;
 
     @Container
     private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer();
@@ -63,16 +65,16 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
         MariaDbConfig.createInitDatabase(CONTAINER_1, DATABASE_1);
         /* metadata database */
         imageRepository.save(IMAGE_1);
-        userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5));
-        containerRepository.saveAll(List.of(CONTAINER_1, CONTAINER_2));
-        databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2));
-        tableRepository.saveAll(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_4, TABLE_5, TABLE_6, TABLE_7));
-        tableColumnRepository.saveAll(Stream.of(TABLE_1_COLUMNS, TABLE_2_COLUMNS, TABLE_3_COLUMNS, TABLE_4_COLUMNS, TABLE_5_COLUMNS, TABLE_6_COLUMNS, TABLE_7_COLUMNS).flatMap(List::stream).toList());
+        userRepository.save(USER_1);
+        containerRepository.save(CONTAINER_1_SIMPLE);
+        databaseRepository.save(DATABASE_1_SIMPLE);
+        tableRepository.save(TABLE_1_SIMPLE);
+        tableColumnRepository.saveAll(TABLE_1_COLUMNS);
     }
 
     @Test
-    public void insert_succeeds() throws TableNotFoundException, QueryMalformedException, DatabaseNotFoundException,
-            InterruptedException {
+    public void insert_succeeds() throws TableNotFoundException, DatabaseNotFoundException, InterruptedException,
+            SQLException {
         final Map<String, Object> request = new HashMap<>() {{
             put("id", 4L);
             put("date", "2023-10-03");
@@ -89,8 +91,8 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
     }
 
     @Test
-    public void insert_onlyMandatoryFields_succeeds() throws TableNotFoundException, QueryMalformedException,
-            DatabaseNotFoundException, InterruptedException {
+    public void insert_onlyMandatoryFields_succeeds() throws TableNotFoundException, DatabaseNotFoundException,
+            InterruptedException, SQLException {
         final Map<String, Object> request = new HashMap<>() {{
             put("id", 5L);
             put("date", "2023-10-04");
@@ -103,4 +105,28 @@ public class QueueServiceIntegrationTest extends BaseUnitTest {
         queueService.insert(DATABASE_1_INTERNALNAME, TABLE_1_INTERNALNAME, request);
     }
 
+    @Test
+    public void insert_databaseNotExists_fails() throws InterruptedException {
+
+        /* pre-condition */
+        Thread.sleep(1000) /* wait for test container some more */;
+
+        /* test */
+        assertThrows(DatabaseNotFoundException.class, () -> {
+            queueService.insert("not_exists", TABLE_1_INTERNALNAME, new HashMap<>());
+        });
+    }
+
+    @Test
+    public void insert_tableNotExists_fails() throws InterruptedException {
+
+        /* pre-condition */
+        Thread.sleep(1000) /* wait for test container some more */;
+
+        /* test */
+        assertThrows(TableNotFoundException.class, () -> {
+            queueService.insert(DATABASE_1_INTERNALNAME, "not_exists", new HashMap<>());
+        });
+    }
+
 }
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e3cff725d951850bfaa128f7c52a340f2afc4be
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java
@@ -0,0 +1,70 @@
+package at.tuwien.service;
+
+import at.tuwien.BaseUnitTest;
+import at.tuwien.annotations.MockAmqp;
+import at.tuwien.annotations.MockOpensearch;
+import at.tuwien.config.MariaDbConfig;
+import at.tuwien.config.MariaDbContainerConfig;
+import at.tuwien.entities.user.User;
+import at.tuwien.exception.DatabaseNotFoundException;
+import at.tuwien.exception.QueryMalformedException;
+import at.tuwien.exception.TableNotFoundException;
+import at.tuwien.exception.UserNotFoundException;
+import at.tuwien.repository.mdb.*;
+import lombok.extern.log4j.Log4j2;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.containers.MariaDBContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Log4j2
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+@Testcontainers
+@MockAmqp
+@MockOpensearch
+public class UserServiceIntegrationTest extends BaseUnitTest {
+
+    @Autowired
+    private UserRepository userRepository;
+
+    @Autowired
+    private UserService userService;
+
+    @BeforeEach
+    public void beforeEach() {
+        userRepository.save(USER_1);
+    }
+
+    @Test
+    public void findByUsername_succeeds() throws UserNotFoundException {
+
+        /* test */
+        final User response = userService.findByUsername(USER_1_USERNAME);
+        assertEquals(USER_1_ID, response.getId());
+    }
+
+    @Test
+    public void findByUsername_fails() {
+
+        /* test */
+        assertThrows(UserNotFoundException.class, () -> {
+            userService.findByUsername(USER_2_USERNAME);
+        });
+    }
+
+}
diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/RabbitMqUtils.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/RabbitMqUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..636ae4db745260e176840e17741f57b46fe40680
--- /dev/null
+++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/RabbitMqUtils.java
@@ -0,0 +1,17 @@
+package at.tuwien.utils;
+
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+public class RabbitMqUtils {
+
+    public static Message buildMessage(String routingKey, String payload, Map<String, Object> headers) {
+        final MessageProperties properties = new MessageProperties();
+        properties.setReceivedRoutingKey(routingKey);
+        properties.setHeaders(headers);
+        return new Message(payload.getBytes(StandardCharsets.UTF_8), properties);
+    }
+}
diff --git a/dbrepo-data-service/rest-service/src/test/resources/application.properties b/dbrepo-data-service/rest-service/src/test/resources/application.properties
index 11033e17a88c840c3e78c6ec70ed61d3c6449e75..54ad577192b2c4b01404e786edd7b89de1234d7e 100644
--- a/dbrepo-data-service/rest-service/src/test/resources/application.properties
+++ b/dbrepo-data-service/rest-service/src/test/resources/application.properties
@@ -19,7 +19,9 @@ spring.sql.init.schema-locations=classpath*:init/schema.sql
 spring.jpa.hibernate.ddl-auto=create
 
 # log
-logging.level.org.hibernate.SQL=trace
+logging.level.at.tuwien.=debug
+logging.level.at.tuwien.service.impl.QueueServiceImpl=trace
+logging.level.at.tuwien.listener.DefaultListener=trace
 
 # rabbitmq
 spring.rabbitmq.host=localhost
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/api/CachedConnection.java b/dbrepo-data-service/services/src/main/java/at/tuwien/api/CachedConnection.java
deleted file mode 100644
index d2da9237118ca5f7be0b9e0f9f677d243c3d0701..0000000000000000000000000000000000000000
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/api/CachedConnection.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package at.tuwien.api;
-
-import at.tuwien.entities.database.Database;
-import at.tuwien.entities.database.table.Table;
-import at.tuwien.exception.TableNotFoundException;
-import com.mchange.v2.c3p0.ComboPooledDataSource;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.Instant;
-import java.util.Optional;
-
-@Getter
-@Setter
-@Builder
-public class CachedConnection {
-
-    private ComboPooledDataSource dataSource;
-
-    private Database database;
-
-    private Instant lastUsed;
-
-    public Table getTable(String internalName) throws TableNotFoundException {
-        final Optional<Table> optional = database.getTables()
-                .stream()
-                .filter(t -> t.getInternalName().equals(internalName))
-                .findFirst();
-        if (optional.isEmpty()) {
-            /* can never happen */
-            throw new TableNotFoundException("Failed to find table with internal name " + internalName);
-        }
-        return optional.get();
-    }
-
-}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..450be2f7df8b52fe493dd498dc0422350bb3ff39
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/MetricsConfig.java
@@ -0,0 +1,15 @@
+package at.tuwien.config;
+
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.observation.aop.ObservedAspect;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MetricsConfig {
+
+    @Bean
+    public ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
+        return new ObservedAspect(observationRegistry);
+    }
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
index 01b3722ada9449a06cf230832d3768596251c26c..272a636e6087d99d9ac16393e907ab5115fc4b2a 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java
@@ -6,6 +6,7 @@ import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.service.QueueService;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import io.micrometer.observation.annotation.Observed;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.amqp.core.Message;
 import org.springframework.amqp.core.MessageListener;
@@ -15,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
+import java.sql.SQLException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -33,6 +35,7 @@ public class DefaultListener implements MessageListener {
     }
 
     @Override
+    @Observed(name = "dbr_message_receive")
     public void onMessage(Message message) {
         final MessageProperties properties = message.getMessageProperties();
         final TypeReference<HashMap<String, Object>> typeRef = new TypeReference<>() {
@@ -46,6 +49,7 @@ public class DefaultListener implements MessageListener {
             log.error("Failed to map database and table names from routing key: is not 3-part");
             return;
         }
+        log.trace("received message with id {} and content length: {} bytes", message.getMessageProperties().getMessageId(), message.getMessageProperties().getContentLength());
         final String database = parts[1];
         final String table = parts[2];
         final Map<String, Object> body;
@@ -54,7 +58,7 @@ public class DefaultListener implements MessageListener {
             queueService.insert(database, table, body);
         } catch (IOException e) {
             log.error("Failed to read object: {}", e.getMessage());
-        } catch (TableNotFoundException | QueryMalformedException | DatabaseNotFoundException e) {
+        } catch (TableNotFoundException | QueryMalformedException | DatabaseNotFoundException | SQLException e) {
             log.error("Failed to insert tuple: {}", e.getMessage());
         }
     }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
index 6649047500d591617ea76f1492787f799f78fee2..29a2f47599838de3989b24d5bc7140b75b6234aa 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java
@@ -1,10 +1,10 @@
 package at.tuwien.service;
 
-import at.tuwien.exception.ContainerNotFoundException;
 import at.tuwien.exception.DatabaseNotFoundException;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.TableNotFoundException;
 
+import java.sql.SQLException;
 import java.util.Map;
 
 public interface QueueService {
@@ -15,5 +15,5 @@ public interface QueueService {
      * @param table    The table name.
      * @param data     The data.
      */
-    void insert(String database, String table, Map<String, Object> data) throws DatabaseNotFoundException, QueryMalformedException, TableNotFoundException;
+    void insert(String database, String table, Map<String, Object> data) throws DatabaseNotFoundException, QueryMalformedException, TableNotFoundException, SQLException;
 }
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceImpl.java
index 6146c08828d7a232b826c833640808fbca4cdd3d..68f665f12bbf776b278f8bedd61010e5bc0718ce 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceImpl.java
@@ -1,10 +1,8 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.CachedConnection;
-import at.tuwien.config.RabbitConfig;
 import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.table.Table;
 import at.tuwien.exception.DatabaseNotFoundException;
-import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.TableNotFoundException;
 import at.tuwien.mapper.DataMapper;
 import at.tuwien.service.DatabaseService;
@@ -12,83 +10,53 @@ import at.tuwien.service.QueueService;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 @Log4j2
 @Service
 public class QueueServiceImpl extends HibernateConnector implements QueueService {
 
     private final DataMapper dataMapper;
-    private final RabbitConfig rabbitMqConfig;
     private final DatabaseService databaseService;
-    private final Map<String, CachedConnection> cachedConnections;
 
     @Autowired
-    public QueueServiceImpl(DataMapper dataMapper, RabbitConfig rabbitMqConfig, DatabaseService databaseService) {
+    public QueueServiceImpl(DataMapper dataMapper, DatabaseService databaseService) {
         this.dataMapper = dataMapper;
-        this.rabbitMqConfig = rabbitMqConfig;
         this.databaseService = databaseService;
-        this.cachedConnections = new HashMap<>();
-    }
-
-    @Scheduled(fixedRate = 5000)
-    @Transactional(readOnly = true)
-    public void updateCachedConnections() {
-        final Instant threshold = Instant.now().minus(rabbitMqConfig.getConnectionTimeout(), ChronoUnit.MILLIS);
-        cachedConnections.entrySet()
-                .stream()
-                .filter(e -> e.getValue().getLastUsed().isAfter(threshold))
-                .forEach(connection -> {
-                    connection.getValue().getDataSource().close();
-                    cachedConnections.remove(connection.getKey());
-                    log.debug("connection for database {} expired", connection.getKey());
-                });
     }
 
     @Override
     @Transactional(readOnly = true)
-    public void insert(String database, String table, Map<String, Object> data) throws DatabaseNotFoundException,
-            QueryMalformedException, TableNotFoundException {
-        /* check if connection can be reused */
-        final CachedConnection cachedConnection = getCachedConnection(database);
-        cachedConnection.setLastUsed(Instant.now());
+    public void insert(String databaseInternalName, String tableInternalName, Map<String, Object> data)
+            throws DatabaseNotFoundException, TableNotFoundException, SQLException {
+        final Database database = databaseService.findByInternalName(databaseInternalName);
+        log.debug("found database with id {} for name {}", database.getId(), databaseInternalName);
+        final Optional<Table> optional = database.getTables()
+                .stream()
+                .filter(t -> t.getInternalName().equals(tableInternalName))
+                .findFirst();
+        if (optional.isEmpty()) {
+            log.error("Failed to insert tuple into table {}: the table does not exist in database with name {}", tableInternalName, databaseInternalName);
+            throw new TableNotFoundException("Failed to insert tuple into table " + tableInternalName + ": the table does not exist in database with name " + databaseInternalName);
+        }
+        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database.getContainer().getImage(),
+                database.getContainer(), database);
         /* run query */
         try {
-            final Connection connection = cachedConnection.getDataSource().getConnection();
-            final PreparedStatement preparedStatement = dataMapper.rabbitMqTupleToInsertOrUpdateQuery(connection, cachedConnection.getTable(table), data);
+            final Connection connection = dataSource.getConnection();
+            final PreparedStatement preparedStatement = dataMapper.rabbitMqTupleToInsertOrUpdateQuery(connection, optional.get(), data);
             preparedStatement.executeUpdate();
-        } catch (SQLException e) {
-            log.error("Failed to insert/update tuple in database {}: {}", database, e.getMessage());
-            throw new QueryMalformedException("Failed to insert/update tuple in database " + database, e);
+            log.trace("successfully inserted tuple");
+        } finally {
+            dataSource.close();
         }
     }
 
-    @Transactional(readOnly = true)
-    public CachedConnection getCachedConnection(String databaseInternalName) throws DatabaseNotFoundException {
-        if (this.cachedConnections.containsKey(databaseInternalName)) {
-            return this.cachedConnections.get(databaseInternalName);
-        }
-        /* create */
-        final Database database = databaseService.findByInternalName(databaseInternalName);
-        final ComboPooledDataSource dataSource = getPrivilegedDataSource(database.getContainer().getImage(),
-                database.getContainer(), database);
-        final CachedConnection cachedConnection = CachedConnection.builder()
-                .dataSource(dataSource)
-                .database(database)
-                .lastUsed(Instant.now())
-                .build();
-        this.cachedConnections.put(databaseInternalName, cachedConnection);
-        log.info("Established connection and added database {} to cache pool", databaseInternalName);
-        return cachedConnection;
-    }
 }
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
index 9efb25050e5538a366d027d44742700a03fdd287..9d4e8f39eaa3bb02e22c4fdaf2ae518dad96285f 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java
@@ -109,7 +109,7 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest {
     public void create_notFound_fails() {
         final ContainerCreateRequestDto request = ContainerCreateRequestDto.builder()
                 .name(CONTAINER_3_NAME)
-                .imageId(IMAGE_2_ID)
+                .imageId(9999L)
                 .build();
 
         /* test */
diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java
index d80f6787e49e6a97ea5e95f1a7e7e8cc058e3c88..e5d864af97f894d1d789f9e61c83c00317172ce5 100644
--- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java
+++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java
@@ -48,12 +48,12 @@ public class ImageServiceIntegrationTest extends BaseUnitTest {
     @Test
     public void create_succeeds() throws ImageAlreadyExistsException {
         final ImageCreateDto request = ImageCreateDto.builder()
-                .name(IMAGE_2_NAME)
-                .version(IMAGE_2_VERSION)
-                .jdbcMethod(IMAGE_2_JDBC)
-                .dialect(IMAGE_2_DIALECT)
-                .driverClass(IMAGE_2_DRIVER)
-                .defaultPort(IMAGE_2_PORT)
+                .name(IMAGE_1_NAME)
+                .version(IMAGE_1_VERSION)
+                .jdbcMethod(IMAGE_1_JDBC)
+                .dialect(IMAGE_1_DIALECT)
+                .driverClass(IMAGE_1_DRIVER)
+                .defaultPort(IMAGE_1_PORT)
                 .build();
         final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
 
diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
index 6fa29160b3969cb28934c3bd33e3ac1522dfd200..fe9a744280e4a0ffb7e3e198952cd729e45076d4 100644
--- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
+++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java
@@ -814,16 +814,6 @@ public abstract class BaseTest {
             .version(IMAGE_1_VERSION)
             .build();
 
-    public final static Long IMAGE_2_ID = 2L;
-    public final static String IMAGE_2_NAME = "mariadb";
-    public final static String IMAGE_2_VERSION = "8.0";
-    public final static Integer IMAGE_2_PORT = 3306;
-    public final static String IMAGE_2_DIALECT = "org.hibernate.dialect.MySQLDialect";
-    public final static String IMAGE_2_DRIVER = "com.mysql.jdbc.Driver";
-    public final static String IMAGE_2_JDBC = "mysql";
-    public final static Long IMAGE_2_SIZE = 12000L;
-    public final static Instant IMAGE_2_BUILT = Instant.now().minus(38, HOURS);
-
     public final static Long CONTAINER_1_ID = 1L;
     public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
     public final static ImageBriefDto CONTAINER_1_IMAGE_BRIEF_DTO = IMAGE_1_BRIEF_DTO;