From 587a5af75d9adee5a3f765261931cd6e8ab6ff43 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 31 Oct 2022 14:58:05 +0100 Subject: refactor(sim/compute): Report exceptions in onStop as suppressed This change updates the implementation of `SimMachineContext` to report exceptions thrown in `onStop` as suppressed exceptions if an exception caused the workload to stop. --- .../org/opendc/simulator/compute/SimMachineTest.kt | 69 +++++++++++++++++ .../compute/workload/SimChainWorkloadTest.kt | 90 +++++++++++++++++++++- 2 files changed, 155 insertions(+), 4 deletions(-) (limited to 'opendc-simulator/opendc-simulator-compute/src/test') diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt index 266839bd..cde6763c 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt @@ -22,6 +22,8 @@ package org.opendc.simulator.compute +import io.mockk.every +import io.mockk.mockk import kotlinx.coroutines.CancellationException import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope @@ -334,4 +336,71 @@ class SimMachineTest { } } } + + @Test + fun testCatchStartFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workload = mockk() + every { workload.onStart(any()) } throws IllegalStateException() + + assertThrows { machine.runWorkload(workload) } + } + + @Test + fun testCatchStopFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workload = mockk() + every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown() } + every { workload.onStop(any()) } throws IllegalStateException() + + assertThrows { machine.runWorkload(workload) } + } + + @Test + fun testCatchShutdownFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workload = mockk() + every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } + + assertThrows { machine.runWorkload(workload) } + } + + @Test + fun testCatchNestedFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workload = mockk() + every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } + every { workload.onStop(any()) } throws IllegalStateException() + + val exc = assertThrows { machine.runWorkload(workload) } + assertEquals(1, exc.cause!!.suppressedExceptions.size) + } } diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt index 6bf05f65..2210374d 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt @@ -28,7 +28,9 @@ import io.mockk.spyk import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.opendc.simulator.compute.SimBareMetalMachine +import org.opendc.simulator.compute.SimMachineContext import org.opendc.simulator.compute.model.MachineModel import org.opendc.simulator.compute.model.MemoryUnit import org.opendc.simulator.compute.model.ProcessingNode @@ -94,7 +96,7 @@ class SimChainWorkloadTest { SimRuntimeWorkload(1000, 1.0) ) - machine.runWorkload(workload) + assertThrows { machine.runWorkload(workload) } assertEquals(0, clock.millis()) } @@ -120,7 +122,7 @@ class SimChainWorkloadTest { SimRuntimeWorkload(1000, 1.0) ) - machine.runWorkload(workload) + assertThrows { machine.runWorkload(workload) } assertEquals(1000, clock.millis()) } @@ -144,7 +146,7 @@ class SimChainWorkloadTest { SimRuntimeWorkload(1000, 1.0) ) - machine.runWorkload(workload) + assertThrows { machine.runWorkload(workload) } assertEquals(1000, clock.millis()) } @@ -169,8 +171,88 @@ class SimChainWorkloadTest { SimRuntimeWorkload(1000, 1.0) ) - machine.runWorkload(workload) + assertThrows { machine.runWorkload(workload) } assertEquals(2000, clock.millis()) } + + @Test + fun testStartAndStopFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workloadA = mockk() + every { workloadA.onStart(any()) } throws IllegalStateException() + every { workloadA.onStop(any()) } throws IllegalStateException() + + val workload = + SimWorkloads.chain( + SimRuntimeWorkload(1000, 1.0), + workloadA + ) + + val exc = assertThrows { machine.runWorkload(workload) } + + assertEquals(2, exc.cause!!.suppressedExceptions.size) + assertEquals(1000, clock.millis()) + } + + @Test + fun testShutdownAndStopFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workloadA = mockk() + every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } + every { workloadA.onStop(any()) } throws IllegalStateException() + + val workload = + SimWorkloads.chain( + SimRuntimeWorkload(1000, 1.0), + workloadA + ) + + val exc = assertThrows { machine.runWorkload(workload) } + + assertEquals(1, exc.cause!!.suppressedExceptions.size) + assertEquals(1000, clock.millis()) + } + + @Test + fun testShutdownAndStartFailure() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create( + graph, + machineModel + ) + + val workloadA = mockk(relaxUnitFun = true) + every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) } + + val workloadB = mockk(relaxUnitFun = true) + every { workloadB.onStart(any()) } throws IllegalStateException() + + val workload = + SimWorkloads.chain( + SimRuntimeWorkload(1000, 1.0), + workloadA, + workloadB + ) + + val exc = assertThrows { machine.runWorkload(workload) } + assertEquals(1, exc.cause!!.suppressedExceptions.size) + assertEquals(1000, clock.millis()) + } } -- cgit v1.2.3 From c9750e52a10157f3838b934fed4f04fae69c539a Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 31 Oct 2022 15:02:37 +0100 Subject: feat(sim/compute): Add support for snapshotting workloads This change updates the interface of `SimWorkload` to support snapshotting workloads. We introduce a new method `snapshot()` to this interface which returns a new `SimWorkload` that can be started at a later point in time and on another `SimMachine`, which continues progress from the moment the workload was snapshotted. --- .../org/opendc/simulator/compute/SimMachineTest.kt | 12 ++++++ .../compute/workload/SimChainWorkloadTest.kt | 43 ++++++++++++++++++---- 2 files changed, 47 insertions(+), 8 deletions(-) (limited to 'opendc-simulator/opendc-simulator-compute/src/test') diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt index cde6763c..2acf6ec7 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt @@ -177,6 +177,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) } @@ -197,6 +199,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) } @@ -217,6 +221,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) assertEquals(1000, clock.millis()) @@ -243,6 +249,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) assertEquals(40, clock.millis()) @@ -266,6 +274,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) assertEquals(4000, clock.millis()) @@ -289,6 +299,8 @@ class SimMachineTest { } override fun onStop(ctx: SimMachineContext) {} + + override fun snapshot(): SimWorkload = TODO() }) assertEquals(4000, clock.millis()) diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt index 2210374d..d0b0efaa 100644 --- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt +++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt @@ -25,6 +25,8 @@ package org.opendc.simulator.compute.workload import io.mockk.every import io.mockk.mockk import io.mockk.spyk +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -67,8 +69,8 @@ class SimChainWorkloadTest { val workload = SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), - SimRuntimeWorkload(1000, 1.0) + SimWorkloads.runtime(1000, 1.0), + SimWorkloads.runtime(1000, 1.0) ) machine.runWorkload(workload) @@ -93,7 +95,7 @@ class SimChainWorkloadTest { val workload = SimWorkloads.chain( workloadA, - SimRuntimeWorkload(1000, 1.0) + SimWorkloads.runtime(1000, 1.0) ) assertThrows { machine.runWorkload(workload) } @@ -117,9 +119,9 @@ class SimChainWorkloadTest { val workload = SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), + SimWorkloads.runtime(1000, 1.0), workloadA, - SimRuntimeWorkload(1000, 1.0) + SimWorkloads.runtime(1000, 1.0) ) assertThrows { machine.runWorkload(workload) } @@ -143,7 +145,7 @@ class SimChainWorkloadTest { val workload = SimWorkloads.chain( workloadA, - SimRuntimeWorkload(1000, 1.0) + SimWorkloads.runtime(1000, 1.0) ) assertThrows { machine.runWorkload(workload) } @@ -166,9 +168,9 @@ class SimChainWorkloadTest { val workload = SimWorkloads.chain( - SimRuntimeWorkload(1000, 1.0), + SimWorkloads.runtime(1000, 1.0), workloadA, - SimRuntimeWorkload(1000, 1.0) + SimWorkloads.runtime(1000, 1.0) ) assertThrows { machine.runWorkload(workload) } @@ -255,4 +257,29 @@ class SimChainWorkloadTest { assertEquals(1, exc.cause!!.suppressedExceptions.size) assertEquals(1000, clock.millis()) } + + @Test + fun testSnapshot() = runSimulation { + val engine = FlowEngine.create(coroutineContext, clock) + val graph = engine.newGraph() + + val machine = SimBareMetalMachine.create(graph, machineModel) + val workload = + SimWorkloads.chain( + SimWorkloads.runtime(1000, 1.0), + SimWorkloads.runtime(1000, 1.0) + ) + + val job = launch { machine.runWorkload(workload) } + delay(500L) + val snapshot = workload.snapshot() + + job.join() + + assertEquals(2000, clock.millis()) + + machine.runWorkload(snapshot) + + assertEquals(3500, clock.millis()) + } } -- cgit v1.2.3