From 46b06fb446e79c390c01953d31d700b8e73da24d Mon Sep 17 00:00:00 2001 From: Georgios Andreadis Date: Mon, 29 Jun 2020 16:04:57 +0200 Subject: Prepare simulator repository for monorepo This change prepares the simulator Git repository for the monorepo residing at https://github.com/atlarge-research.com/opendc. To accomodate for this, we move all files into a simulator subdirectory. --- .../core/image/FlopsApplicationImageTest.kt | 78 ++++++++++ .../metal/driver/SimpleBareMetalDriverTest.kt | 88 +++++++++++ .../metal/service/SimpleProvisioningServiceTest.kt | 73 +++++++++ .../atlarge/opendc/compute/virt/HypervisorTest.kt | 167 +++++++++++++++++++++ 4 files changed, 406 insertions(+) create mode 100644 simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt create mode 100644 simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt create mode 100644 simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt create mode 100644 simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt (limited to 'simulator/opendc/opendc-compute/src/test') diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt new file mode 100644 index 00000000..417db77d --- /dev/null +++ b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt @@ -0,0 +1,78 @@ +/* + * MIT License + * + * Copyright (c) 2020 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.compute.core.image + +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.UUID + +/** + * Test suite for [FlopsApplicationImage] + */ +@DisplayName("FlopsApplicationImage") +internal class FlopsApplicationImageTest { + @Test + fun `flops must be non-negative`() { + assertThrows("FLOPs must be non-negative") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), -1, 1) + } + } + + @Test + fun `cores cannot be zero`() { + assertThrows("Cores cannot be zero") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1, 0) + } + } + + @Test + fun `cores cannot be negative`() { + assertThrows("Cores cannot be negative") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1, -1) + } + } + + @Test + fun `utilization cannot be zero`() { + assertThrows("Utilization cannot be zero") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1, 1, 0.0) + } + } + + @Test + fun `utilization cannot be negative`() { + assertThrows("Utilization cannot be negative") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1, 1, -1.0) + } + } + + @Test + fun `utilization cannot be larger than one`() { + assertThrows("Utilization cannot be larger than one") { + FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1, 1, 2.0) + } + } +} diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt new file mode 100644 index 00000000..071c0626 --- /dev/null +++ b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt @@ -0,0 +1,88 @@ +/* + * MIT License + * + * Copyright (c) 2020 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.compute.metal.driver + +import com.atlarge.odcsim.SimulationEngineProvider +import com.atlarge.odcsim.simulationContext +import com.atlarge.opendc.compute.core.ProcessingNode +import com.atlarge.opendc.compute.core.ProcessingUnit +import com.atlarge.opendc.compute.core.ServerEvent +import com.atlarge.opendc.compute.core.ServerState +import com.atlarge.opendc.compute.core.image.FlopsApplicationImage +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import java.util.ServiceLoader +import java.util.UUID + +internal class SimpleBareMetalDriverTest { + /** + * A smoke test for the bare-metal driver. + */ + @Test + fun smoke() { + var finalState: ServerState = ServerState.BUILD + val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() + val system = provider("sim") + val root = system.newDomain(name = "root") + root.launch { + val dom = root.newDomain(name = "driver") + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4) + val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) } + val driver = SimpleBareMetalDriver(dom, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) + val image = FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1_000, 2) + + // Batch driver commands + withContext(dom.coroutineContext) { + driver.init() + driver.setImage(image) + val server = driver.start().server!! + driver.usage + .onEach { println("${simulationContext.clock.millis()} $it") } + .launchIn(this) + server.events.collect { event -> + when (event) { + is ServerEvent.StateChanged -> { + println("${simulationContext.clock.millis()} $event") + finalState = event.server.state + } + } + } + } + } + + runBlocking { + system.run() + system.terminate() + } + + assertEquals(ServerState.SHUTOFF, finalState) + } +} diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt new file mode 100644 index 00000000..f8bd786e --- /dev/null +++ b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt @@ -0,0 +1,73 @@ +/* + * MIT License + * + * Copyright (c) 2020 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.compute.metal.service + +import com.atlarge.odcsim.SimulationEngineProvider +import com.atlarge.opendc.compute.core.ProcessingNode +import com.atlarge.opendc.compute.core.ProcessingUnit +import com.atlarge.opendc.compute.core.image.FlopsApplicationImage +import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Test +import java.util.ServiceLoader +import java.util.UUID + +/** + * Test suite for the [SimpleProvisioningService]. + */ +internal class SimpleProvisioningServiceTest { + /** + * A basic smoke test. + */ + @Test + fun smoke() { + val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() + val system = provider("sim") + val root = system.newDomain(name = "root") + root.launch { + val image = FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1000, 2) + val dom = root.newDomain("provisioner") + + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4) + val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) } + val driver = SimpleBareMetalDriver(dom.newDomain(), UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) + + val provisioner = SimpleProvisioningService(dom) + provisioner.create(driver) + delay(5) + val nodes = provisioner.nodes() + val node = provisioner.deploy(nodes.first(), image) + node.server!!.events.collect { println(it) } + } + + runBlocking { + system.run() + system.terminate() + } + } +} diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt new file mode 100644 index 00000000..ca00fc94 --- /dev/null +++ b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt @@ -0,0 +1,167 @@ +/* + * MIT License + * + * Copyright (c) 2020 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.compute.virt + +import com.atlarge.odcsim.SimulationEngineProvider +import com.atlarge.opendc.compute.core.ProcessingUnit +import com.atlarge.opendc.compute.core.Flavor +import com.atlarge.opendc.compute.core.ProcessingNode +import com.atlarge.opendc.compute.core.image.FlopsApplicationImage +import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment +import com.atlarge.opendc.compute.core.image.VmImage +import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver +import com.atlarge.opendc.compute.virt.driver.VirtDriver +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll +import java.util.ServiceLoader +import java.util.UUID + +/** + * Basic test-suite for the hypervisor. + */ +internal class HypervisorTest { + /** + * A smoke test for the bare-metal driver. + */ + @OptIn(ExperimentalCoroutinesApi::class) + @Test + @Disabled + fun smoke() { + val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() + val system = provider("test") + val root = system.newDomain("root") + + root.launch { + val vmm = HypervisorImage + val workloadA = FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 1_000, 1) + val workloadB = FlopsApplicationImage(UUID.randomUUID(), "", emptyMap(), 2_000, 1) + + val driverDom = root.newDomain("driver") + + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) + val cpus = List(1) { ProcessingUnit(cpuNode, it, 2000.0) } + val metalDriver = SimpleBareMetalDriver(driverDom, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) + + metalDriver.init() + metalDriver.setImage(vmm) + val node = metalDriver.start() + node.server?.events?.onEach { println(it) }?.launchIn(this) + + delay(5) + + val flavor = Flavor(1, 0) + val vmDriver = metalDriver.refresh().server!!.services[VirtDriver] + vmDriver.events.onEach { println(it) }.launchIn(this) + val vmA = vmDriver.spawn("a", workloadA, flavor) + vmA.events.onEach { println(it) }.launchIn(this) + val vmB = vmDriver.spawn("b", workloadB, flavor) + vmB.events.onEach { println(it) }.launchIn(this) + } + + runBlocking { + system.run() + system.terminate() + } + } + + /** + * Test overcommissioning of a hypervisor. + */ + @Test + fun overcommission() { + val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() + val system = provider("test") + val root = system.newDomain("root") + + var requestedBurst = 0L + var grantedBurst = 0L + var overcommissionedBurst = 0L + + root.launch { + val vmm = HypervisorImage + val duration = 5 * 60L + val vmImageA = VmImage(UUID.randomUUID(), "", emptyMap(), sequenceOf( + FlopsHistoryFragment(0, 28L * duration, duration * 1000, 28.0, 2), + FlopsHistoryFragment(0, 3500L * duration, duration * 1000, 3500.0, 2), + FlopsHistoryFragment(0, 0, duration * 1000, 0.0, 2), + FlopsHistoryFragment(0, 183L * duration, duration * 1000, 183.0, 2) + ), 2, 0) + val vmImageB = VmImage(UUID.randomUUID(), "", emptyMap(), sequenceOf( + FlopsHistoryFragment(0, 28L * duration, duration * 1000, 28.0, 2), + FlopsHistoryFragment(0, 3100L * duration, duration * 1000, 3100.0, 2), + FlopsHistoryFragment(0, 0, duration * 1000, 0.0, 2), + FlopsHistoryFragment(0, 73L * duration, duration * 1000, 73.0, 2) + ), 2, 0) + + val driverDom = root.newDomain("driver") + + val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) + val cpus = List(2) { ProcessingUnit(cpuNode, it, 3200.0) } + val metalDriver = SimpleBareMetalDriver(driverDom, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) + + metalDriver.init() + metalDriver.setImage(vmm) + metalDriver.start() + + delay(5) + + val flavor = Flavor(2, 0) + val vmDriver = metalDriver.refresh().server!!.services[VirtDriver] + vmDriver.events + .onEach { event -> + when (event) { + is HypervisorEvent.SliceFinished -> { + requestedBurst += event.requestedBurst + grantedBurst += event.grantedBurst + overcommissionedBurst += event.overcommissionedBurst + } + } + } + .launchIn(this) + + vmDriver.spawn("a", vmImageA, flavor) + vmDriver.spawn("b", vmImageB, flavor) + } + + runBlocking { + system.run() + system.terminate() + } + + assertAll( + { assertEquals(2073600, requestedBurst, "Requested Burst does not match") }, + { assertEquals(2013600, grantedBurst, "Granted Burst does not match") }, + { assertEquals(60000, overcommissionedBurst, "Overcommissioned Burst does not match") } + ) + } +} -- cgit v1.2.3