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