From 13d08d280188433de7feee8be82c4e3ecbade667 Mon Sep 17 00:00:00 2001
From: "stu126940@mail.uni-kiel.de" <stu126940@mail.uni-kiel.de>
Date: Mon, 21 Jun 2021 22:47:27 +0200
Subject: [PATCH] add tests

add unit test for K8sManager,
add unit test for K8sResourceLoader,

introduce a K8s mock server
---
 theodolite-quarkus/build.gradle               |   4 +
 .../theodolite/k8s/K8sResourceLoader.kt       |  11 ++
 .../theodolite/k8s/ServiceMonitorWrapper.kt   |   2 +-
 .../kotlin/theodolite/k8s/K8sManagerTest.kt   | 151 ++++++++++++++++++
 .../theodolite/k8s/K8sResourceLoaderTest.kt   |  86 ++++++++++
 .../k8s-resource-files/test-configmap.yaml    |   6 +
 .../k8s-resource-files/test-deployment.yaml   |  17 ++
 .../test-service-monitor.yaml                 |   7 +
 .../k8s-resource-files/test-service.yaml      |   9 ++
 .../k8s-resource-files/test-statefulset.yaml  |  16 ++
 10 files changed, 308 insertions(+), 1 deletion(-)
 create mode 100644 theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt
 create mode 100644 theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-configmap.yaml
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-deployment.yaml
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-service-monitor.yaml
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-service.yaml
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-statefulset.yaml

diff --git a/theodolite-quarkus/build.gradle b/theodolite-quarkus/build.gradle
index 8c0a13d1f..0062fecd9 100644
--- a/theodolite-quarkus/build.gradle
+++ b/theodolite-quarkus/build.gradle
@@ -31,6 +31,10 @@ dependencies {
     testImplementation 'io.quarkus:quarkus-junit5'
     testImplementation 'io.rest-assured:rest-assured'
     testImplementation 'org.junit-pioneer:junit-pioneer:1.4.0'
+    testImplementation group: 'io.fabric8', name: 'kubernetes-server-mock', version: '4.6.0'
+
+
+
 }
 
 group 'theodolite'
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt
index fd5ec3b2e..784114d27 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/K8sResourceLoader.kt
@@ -60,6 +60,16 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
         return loadGenericResource(path) { x: String -> client.configMaps().load(x).get() }
     }
 
+    /**
+     * Parses a StatefulSet from a StatefulSet yaml
+     * @param path of the yaml file
+     * @return StatefulSet from fabric8
+     */
+    private fun loadStatefulSet(path: String): KubernetesResource {
+        return loadGenericResource(path) { x: String -> client.apps().statefulSets().load(x).get() }
+
+    }
+
     /**
      * Generic helper function to load a resource.
      * @param path of the resource
@@ -96,6 +106,7 @@ class K8sResourceLoader(private val client: NamespacedKubernetesClient) {
             "Service" -> loadService(path)
             "ServiceMonitor" -> loadServiceMonitor(path)
             "ConfigMap" -> loadConfigmap(path)
+            "StatefulSet" -> loadStatefulSet(path)
             else -> {
                 logger.error { "Error during loading of unspecified resource Kind" }
                 throw java.lang.IllegalArgumentException("error while loading resource with kind: $kind")
diff --git a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
index 56452d749..a1d33dc73 100644
--- a/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
+++ b/theodolite-quarkus/src/main/kotlin/theodolite/k8s/ServiceMonitorWrapper.kt
@@ -49,7 +49,7 @@ class ServiceMonitorWrapper(private val serviceMonitor: Map<String, String>) : C
     /**
      * @throws NullPointerException if name or metadata is null
      */
-    private fun getServiceMonitorName(): String {
+    fun getServiceMonitorName(): String {
         val smAsMap = this.serviceMonitor["metadata"]!! as Map<String, String>
         return smAsMap["name"]!!
     }
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt
new file mode 100644
index 000000000..cb52e0ae1
--- /dev/null
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sManagerTest.kt
@@ -0,0 +1,151 @@
+package theodolite.k8s
+
+import io.fabric8.kubernetes.api.model.*
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.api.model.apps.StatefulSetBuilder
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer
+import io.quarkus.test.junit.QuarkusTest
+import mu.KotlinLogging
+import org.json.JSONObject
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Test
+
+
+private val logger = KotlinLogging.logger {}
+
+@QuarkusTest
+class K8sManagerTest {
+    private final val server = KubernetesServer(false,true)
+    private final val testResourcePath = "./src/test/resources/k8s-resource-files/"
+
+    private final val resourceName = "test-resource"
+    private final val metadata: ObjectMeta = ObjectMetaBuilder().withName(resourceName).build()
+
+
+    val defaultDeployment: Deployment = DeploymentBuilder()
+        .withMetadata(metadata)
+        .withNewSpec()
+            .editOrNewSelector()
+                .withMatchLabels(mapOf("app" to "test"))
+            .endSelector()
+        .endSpec()
+        .build()
+
+    val defaultStatefulSet: StatefulSet = StatefulSetBuilder()
+        .withMetadata(metadata)
+        .withNewSpec()
+            .editOrNewSelector()
+                .withMatchLabels(mapOf("app" to "test"))
+            .endSelector()
+        .endSpec()
+        .build()
+
+    val defaultService: Service = ServiceBuilder()
+        .withMetadata(metadata)
+        .build()
+
+    val defaultConfigMap: ConfigMap = ConfigMapBuilder()
+        .withMetadata(metadata)
+        .build()
+
+    @BeforeEach
+    fun setUp() {
+        server.before()
+
+    }
+
+    @AfterEach
+    fun tearDown() {
+        server.after()
+
+    }
+
+    @Test
+    @DisplayName("Test handling of Deployments")
+    fun handleDeploymentTest() {
+        val manager = K8sManager(server.client)
+
+        manager.deploy(defaultDeployment)
+        assertEquals(1, server.client.apps().deployments().list().items.size)
+        assertEquals(resourceName, server.client.apps().deployments().list().items.first().metadata.name)
+
+        manager.remove(defaultDeployment)
+        assertEquals(0, server.client.apps().deployments().list().items.size)
+    }
+
+    @Test
+    @DisplayName("Test handling of StatefulSets")
+    fun handleStatefulSetTest() {
+        val manager = K8sManager(server.client)
+
+        manager.deploy(defaultStatefulSet)
+        assertEquals(1, server.client.apps().statefulSets().list().items.size)
+        assertEquals(resourceName, server.client.apps().statefulSets().list().items.first().metadata.name)
+
+        manager.remove(defaultStatefulSet)
+        assertEquals(0, server.client.apps().statefulSets().list().items.size)
+    }
+
+    @Test
+    @DisplayName("Test handling of Services")
+    fun handleServiceTest() {
+        val manager = K8sManager(server.client)
+
+        manager.deploy(defaultService)
+        assertEquals(1, server.client.services().list().items.size)
+        assertEquals(resourceName, server.client.services().list().items.first().metadata.name)
+
+        manager.remove(defaultService)
+        assertEquals(0, server.client.services().list().items.size)
+    }
+
+
+    @Test
+    @DisplayName("Test handling of ConfigMaps")
+    fun handleConfigMapTest() {
+        val manager = K8sManager(server.client)
+
+        manager.deploy(defaultConfigMap)
+        assertEquals(1, server.client.configMaps().list().items.size)
+        assertEquals(resourceName, server.client.configMaps().list().items.first().metadata.name)
+
+        manager.remove(defaultConfigMap)
+        assertEquals(0, server.client.configMaps().list().items.size)
+    }
+
+    @Test
+    @DisplayName("Test handling of ServiceMontors")
+    fun handleServiceMonitorTest() {
+        val manager = K8sManager(server.client)
+        val servicemonitor = K8sResourceLoader(server.client)
+            .loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml")
+
+        val serviceMonitorContext = K8sContextFactory().create(
+            api = "v1",
+            scope = "Namespaced",
+            group = "monitoring.coreos.com",
+            plural = "servicemonitors"
+        )
+        manager.deploy(servicemonitor)
+
+        var serviceMonitors = JSONObject(server.client.customResource(serviceMonitorContext).list())
+            .getJSONArray("items")
+
+        assertEquals(1,serviceMonitors.length())
+        assertEquals("test-service-monitor", serviceMonitors.getJSONObject(0).getJSONObject("metadata").getString("name"))
+
+        manager.remove(servicemonitor)
+
+        serviceMonitors = JSONObject(server.client.customResource(serviceMonitorContext).list())
+            .getJSONArray("items")
+
+        assertEquals(0,serviceMonitors.length())
+    }
+
+
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt
new file mode 100644
index 000000000..0531782bf
--- /dev/null
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/k8s/K8sResourceLoaderTest.kt
@@ -0,0 +1,86 @@
+package theodolite.k8s
+
+import io.fabric8.kubernetes.api.model.ConfigMap
+import io.fabric8.kubernetes.api.model.Service
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.api.model.apps.StatefulSet
+import io.fabric8.kubernetes.client.server.mock.KubernetesServer
+import io.quarkus.test.junit.QuarkusTest
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Test
+
+@QuarkusTest
+class K8sResourceLoaderTest {
+    private final val server = KubernetesServer(false,true)
+    private final val testResourcePath = "./src/test/resources/k8s-resource-files/"
+
+    @BeforeEach
+    fun setUp() {
+        server.before()
+
+    }
+
+    @AfterEach
+    fun tearDown() {
+        server.after()
+
+    }
+
+    @Test
+    @DisplayName("Test loading of Deployments")
+    fun loadDeploymentTest() {
+        val loader = K8sResourceLoader(server.client)
+        val resource = loader.loadK8sResource("Deployment", testResourcePath + "test-deployment.yaml")
+
+        assertTrue(resource is Deployment)
+        assertTrue(resource.toString().contains("name=test-deployment"))
+    }
+
+    @Test
+    @DisplayName("Test loading of StatefulSet")
+    fun loadStatefulSetTest() {
+        val loader = K8sResourceLoader(server.client)
+        val resource = loader.loadK8sResource("StatefulSet", testResourcePath + "test-statefulset.yaml")
+
+        assertTrue(resource is StatefulSet)
+        assertTrue(resource.toString().contains("name=test-statefulset"))
+    }
+
+    @Test
+    @DisplayName("Test loading of Service")
+    fun loadServiceTest() {
+        val loader = K8sResourceLoader(server.client)
+        val resource = loader.loadK8sResource("Service", testResourcePath + "test-service.yaml")
+
+        assertTrue(resource is Service)
+        assertTrue(resource.toString().contains("name=test-service"))
+    }
+
+    @Test
+    @DisplayName("Test loading of ConfigMap")
+    fun loadConfigMapTest() {
+        val loader = K8sResourceLoader(server.client)
+        val resource = loader.loadK8sResource("ConfigMap", testResourcePath + "test-configmap.yaml")
+
+        assertTrue(resource is ConfigMap)
+        assertTrue(resource.toString().contains("name=test-configmap"))
+    }
+
+    @Test
+    @DisplayName("Test loading of ServiceMonitors")
+    fun loadServiceMonitorTest() {
+        val loader = K8sResourceLoader(server.client)
+        val resource = loader.loadK8sResource("ServiceMonitor", testResourcePath + "test-service-monitor.yaml")
+
+        assertTrue(resource is ServiceMonitorWrapper)
+        if (resource is ServiceMonitorWrapper) {
+            assertEquals(resource.getServiceMonitorName(),"test-service-monitor")
+
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-configmap.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-configmap.yaml
new file mode 100644
index 000000000..dce11c991
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-configmap.yaml
@@ -0,0 +1,6 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: test-configmap
+data:
+  test: test
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-deployment.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-deployment.yaml
new file mode 100644
index 000000000..e9c4bda12
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-deployment.yaml
@@ -0,0 +1,17 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: test-deployment
+spec:
+  selector:
+    matchLabels:
+      app: titan-ccp-aggregation
+  template:
+    metadata:
+      labels:
+        app: titan-ccp-aggregation
+    spec:
+      containers:
+        - name: uc-application
+          image: ghcr.io/cau-se/theodolite-uc1-kstreams-app:latest
+
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service-monitor.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service-monitor.yaml
new file mode 100644
index 000000000..e8a0e52e1
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service-monitor.yaml
@@ -0,0 +1,7 @@
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  labels:
+    app: titan-ccp-aggregation
+    appScope: titan-ccp
+  name: test-service-monitor
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service.yaml
new file mode 100644
index 000000000..471b6db83
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-service.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: test-service
+  labels:
+    app: titan-ccp-aggregation
+spec:
+  selector:
+    app: titan-ccp-aggregation
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-statefulset.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-statefulset.yaml
new file mode 100644
index 000000000..6a8810e9e
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-statefulset.yaml
@@ -0,0 +1,16 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: test-statefulset
+spec:
+  selector:
+    matchLabels:
+      app: nginx
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      containers:
+        - name: nginx
+          image: k8s.gcr.io/nginx-slim:0.8
-- 
GitLab