From 9f895d26b19c4d0d6883df0fcc5ad7ba99377eb5 Mon Sep 17 00:00:00 2001
From: "stu126940@mail.uni-kiel.de" <stu126940@mail.uni-kiel.de>
Date: Thu, 24 Jun 2021 11:15:35 +0200
Subject: [PATCH] add test for executionEventHandler

---
 .../execution/operator/ControllerDummy.kt     |  45 ++--
 .../operator/ExecutionEventHandlerTest.kt     | 216 ++++++++++++++++++
 .../test-execution-update.yaml                |  28 +++
 3 files changed, 264 insertions(+), 25 deletions(-)
 create mode 100644 theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
 create mode 100644 theodolite-quarkus/src/test/resources/k8s-resource-files/test-execution-update.yaml

diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ControllerDummy.kt b/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ControllerDummy.kt
index a729c5013..79306ecdc 100644
--- a/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ControllerDummy.kt
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ControllerDummy.kt
@@ -13,12 +13,30 @@ private const val EXECUTION_PLURAL = "executions"
 private const val BENCHMARK_SINGULAR = "benchmark"
 private const val BENCHMARK_PLURAL = "benchmarks"
 private const val API_VERSION = "v1"
-private const val RESYNC_PERIOD = 10 * 60 * 1000.toLong()
 private const val GROUP = "theodolite.com"
 
 class ControllerDummy(val client: NamespacedKubernetesClient) {
 
-    private lateinit var controller: TheodoliteController
+    private var controller: TheodoliteController
+    val executionContext = K8sContextFactory()
+            .create(
+                API_VERSION,
+                SCOPE,
+                GROUP,
+                EXECUTION_PLURAL
+            )
+    val benchmarkContext = K8sContextFactory()
+            .create(
+                API_VERSION,
+                SCOPE,
+                GROUP,
+                BENCHMARK_PLURAL
+            )
+
+    val executionStateHandler = ExecutionStateHandler(
+        context = executionContext,
+        client = client
+    )
 
     fun getController(): TheodoliteController {
         return this.controller
@@ -37,24 +55,6 @@ class ControllerDummy(val client: NamespacedKubernetesClient) {
             BenchmarkCRD::class.java
         )
 
-        val contextFactory = K8sContextFactory()
-        val executionContext =
-            contextFactory
-                .create(
-                    API_VERSION,
-                    SCOPE,
-                    GROUP,
-                    EXECUTION_PLURAL
-                )
-        val benchmarkContext =
-            contextFactory
-                .create(
-                    API_VERSION,
-                    SCOPE,
-                    GROUP,
-                    BENCHMARK_PLURAL
-                )
-
         val executionCRDClient: MixedOperation<
                 ExecutionCRD,
                 BenchmarkExecutionList,
@@ -73,11 +73,6 @@ class ControllerDummy(val client: NamespacedKubernetesClient) {
             DoneableBenchmark::class.java
         )
 
-        val executionStateHandler = ExecutionStateHandler(
-            context = executionContext,
-            client = client
-        )
-
         val appResource = System.getenv("THEODOLITE_APP_RESOURCES") ?: "./config"
         this.controller =
             TheodoliteController(
diff --git a/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt b/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
new file mode 100644
index 000000000..9d030f77a
--- /dev/null
+++ b/theodolite-quarkus/src/test/kotlin/theodolite/execution/operator/ExecutionEventHandlerTest.kt
@@ -0,0 +1,216 @@
+package theodolite.execution.operator
+
+import io.fabric8.kubernetes.api.model.KubernetesResource
+import io.fabric8.kubernetes.client.informers.SharedInformerFactory
+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.BeforeEach
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Test
+import theodolite.k8s.K8sManager
+import theodolite.k8s.K8sResourceLoader
+import theodolite.model.crd.BenchmarkExecutionList
+import theodolite.model.crd.ExecutionCRD
+import theodolite.model.crd.States
+import java.lang.Thread.sleep
+
+
+private const val RESYNC_PERIOD = 1000 * 1000.toLong()
+
+
+@QuarkusTest
+class ExecutionEventHandlerTest {
+    private final val server = KubernetesServer(false, true)
+    private val testResourcePath = "./src/test/resources/k8s-resource-files/"
+    private final val executionName = "example-execution"
+    lateinit var factory: SharedInformerFactory
+    lateinit var executionVersion1: KubernetesResource
+    lateinit var executionVersion2: KubernetesResource
+    lateinit var stateHandler: ExecutionStateHandler
+    lateinit var manager: K8sManager
+
+    @BeforeEach
+    fun setUp() {
+        server.before()
+        val controllerDummy = ControllerDummy(server.client)
+
+        this.factory = server.client.informers()
+        val informerExecution = factory
+            .sharedIndexInformerForCustomResource(
+            controllerDummy.executionContext,
+            ExecutionCRD::class.java,
+            BenchmarkExecutionList::class.java,
+            RESYNC_PERIOD
+        )
+
+        informerExecution.addEventHandler(ExecutionHandler(
+            controller = controllerDummy.getController(),
+            stateHandler = controllerDummy.executionStateHandler))
+
+        this.executionVersion1 = K8sResourceLoader(server.client)
+            .loadK8sResource("Execution", testResourcePath + "test-execution.yaml")
+
+        this.executionVersion2 = K8sResourceLoader(server.client)
+            .loadK8sResource("Execution", testResourcePath + "test-execution-update.yaml")
+
+        this.stateHandler = ControllerDummy(server.client).executionStateHandler
+
+        this.manager = K8sManager((server.client))
+    }
+
+    @AfterEach
+    fun tearDown(){
+        server.after()
+        factory.stopAllRegisteredInformers()
+    }
+
+    @Test
+    @DisplayName("Test onAdd method for executions without execution state")
+    fun testWithoutState(){
+        manager.deploy(executionVersion1)
+        factory.startAllRegisteredInformers()
+        sleep(500)
+        assertEquals(
+            States.PENDING,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+    }
+
+    @Test
+    @DisplayName("Test onAdd method for executions with execution state `RUNNING`")
+    fun testWithStateIsRunning(){
+        manager.deploy(executionVersion1)
+        stateHandler
+            .setExecutionState(
+                resourceName = executionName,
+                status = States.RUNNING
+            )
+        factory.startAllRegisteredInformers()
+        sleep(500)
+        assertEquals(
+            States.RESTART,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+    }
+
+    @Test
+    @DisplayName("Test onUpdate method for execution with execution state `PENDING`")
+    fun testOnUpdatePending() {
+        manager.deploy(executionVersion1)
+
+        factory.startAllRegisteredInformers()
+        sleep(500)
+
+        assertEquals(
+            States.PENDING,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+
+        manager.deploy(executionVersion2)
+        assertEquals(
+            States.PENDING,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+
+    }
+
+    @Test
+    @DisplayName("Test onUpdate method for execution with execution state `FINISHED`")
+    fun testOnUpdateFinished() {
+        manager.deploy(executionVersion1)
+        factory.startAllRegisteredInformers()
+        sleep(500)
+
+        stateHandler.setExecutionState(
+            resourceName = executionName,
+            status = States.FINISHED
+        )
+
+        manager.deploy(executionVersion2)
+        sleep(500)
+
+        assertEquals(
+            States.PENDING,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+    }
+
+    @Test
+    @DisplayName("Test onUpdate method for execution with execution state `FAILURE`")
+    fun testOnUpdateFailure() {
+        manager.deploy(executionVersion1)
+        factory.startAllRegisteredInformers()
+        sleep(500)
+
+        stateHandler.setExecutionState(
+            resourceName = executionName,
+            status = States.FAILURE        )
+
+        manager.deploy(executionVersion2)
+        sleep(500)
+
+        assertEquals(
+            States.PENDING,
+            stateHandler.getExecutionState(
+                resourceName = executionName
+            )
+        )
+    }
+
+
+    @Test
+    @DisplayName("Test onUpdate method for execution with execution state `RUNNING`")
+    fun testOnUpdateRunning() {
+        manager.deploy(executionVersion1)
+        factory.startAllRegisteredInformers()
+        sleep(500)
+
+        stateHandler.setExecutionState(
+            resourceName = executionName,
+            status = States.RUNNING
+        )
+
+        manager.deploy(executionVersion2)
+        sleep(500)
+
+        assertEquals(
+            States.RESTART,
+            stateHandler.getExecutionState(
+                resourceName = executionName)
+        )
+    }
+
+    @Test
+    @DisplayName("Test onUpdate method for execution with execution state `RESTART`")
+    fun testOnUpdateRestart() {
+        manager.deploy(executionVersion1)
+        factory.startAllRegisteredInformers()
+        sleep(500)
+
+        stateHandler.setExecutionState(
+            resourceName = executionName,
+            status = States.RESTART
+        )
+
+        manager.deploy(executionVersion2)
+        sleep(500)
+
+        assertEquals(
+            States.RESTART,
+            stateHandler.getExecutionState(
+                resourceName = executionName)
+        )
+    }
+}
\ No newline at end of file
diff --git a/theodolite-quarkus/src/test/resources/k8s-resource-files/test-execution-update.yaml b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-execution-update.yaml
new file mode 100644
index 000000000..4ef4fdc00
--- /dev/null
+++ b/theodolite-quarkus/src/test/resources/k8s-resource-files/test-execution-update.yaml
@@ -0,0 +1,28 @@
+apiVersion: theodolite.com/v1
+kind: execution
+metadata:
+  name: example-execution
+spec:
+  name: test
+  benchmark: "uc1-kstreams-update"
+  load:
+    loadType: "NumSensors"
+    loadValues: [25000, 50000, 75000, 100000, 125000, 150000]
+  resources:
+    resourceType: "Instances"
+    resourceValues: [1, 2, 3, 4, 5]
+  slos:
+    - sloType: "lag trend"
+      threshold: 2000
+      prometheusUrl: "http://prometheus-operated:9090"
+      externalSloUrl: "http://localhost:80/evaluate-slope"
+      offset: 0
+      warmup: 60 # in seconds
+  execution:
+    strategy: "LinearSearch"
+    duration: 300 # in seconds
+    repetitions: 1
+    loadGenerationDelay: 30 # in seconds
+    restrictions:
+      - "LowerBound"
+  configOverrides: []
-- 
GitLab