diff options
Diffstat (limited to 'odcsim-core')
11 files changed, 641 insertions, 0 deletions
diff --git a/odcsim-core/build.gradle b/odcsim-core/build.gradle new file mode 100644 index 00000000..3ae40a0d --- /dev/null +++ b/odcsim-core/build.gradle @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2017 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. + */ + +/* Build configuration */ +apply from: '../gradle/kotlin.gradle' +apply plugin: 'java-library' + +/* Project configuration */ +repositories { + jcenter() +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib" + + testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version" + testImplementation "org.junit.platform:junit-platform-launcher:$junit_platform_version" +} + +/* Create configuration for test suite used by implementors */ +task testJar(type: Jar, dependsOn: testClasses) { + baseName = "test-${project.archivesBaseName}" + from sourceSets.test.output +} + +configurations { + tests +} + +artifacts { + tests testJar +} + + diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt new file mode 100644 index 00000000..5a16c4d1 --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt @@ -0,0 +1,59 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * Represents the context in which the execution of an actor's behavior takes place. + * + * @param T The shape of the messages the actor accepts. + */ +interface ActorContext<in T : Any> { + /** + * The identity of the actor, bound to the lifecycle of this actor instance. + */ + val self: ActorRef<T> + + /** + * The point of time within the simulation. + */ + val time: Instant + + /** + * Spawn a child actor from the given [Behavior] and with the specified name. + * + * @param name The name of the child actor to spawn. + * @param behavior The behavior of the child actor to spawn. + * @return A reference to the child that has/will be spawned. + */ + fun <U : Any> spawn(name: String, behavior: Behavior<U>): ActorRef<U> + + /** + * Request the specified child actor to be stopped in asynchronous fashion. + * + * @param child The reference to the child actor to stop. + * @return `true` if the ref points to a child actor, otherwise `false`. + */ + fun <U : Any> stop(child: ActorRef<U>): Boolean +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt new file mode 100644 index 00000000..cc3b19af --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt @@ -0,0 +1,137 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +import java.io.Serializable + +/** + * An actor path represents the unique path to a specific actor instance within an [ActorSystem]. + */ +sealed class ActorPath : Comparable<ActorPath>, Serializable { + /** + * The name of the actor that this path refers to. + */ + abstract val name: String + + /** + * The path for the parent actor. + */ + abstract val parent: ActorPath + + /** + * Walk up the tree to obtain and return the [ActorPath.Root]. + */ + abstract val root: Root + + /** + * Create a new child actor path. + */ + fun child(name: String): ActorPath = Child(this, name) + + /** + * Recursively create a descendant’s path by appending all child names. + */ + fun descendant(children: Iterable<String>): ActorPath = children.fold(this) { parent, name -> + if (name.isNotBlank()) child(name) else parent + } + + /** + * Root of the hierarchy of [ActorPath]s. There is exactly root per [ActorSystem]. + */ + data class Root(override val name: String = "/") : ActorPath() { + init { + require(name.length == 1 || name.indexOf('/', 1) == -1) { + "/ may only exist at the beginning of the root actors name" + } + require(name.indexOf('#') == -1) { "# may not exist in a path component"} + } + + override val parent: ActorPath = this + + override val root: Root = this + + /** + * Compare the [specified][other] path with this root node for order. If both paths are roots, compare their + * name, otherwise the root is ordered higher. + * + * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater + * than the specified path. + */ + override fun compareTo(other: ActorPath): Int = if (other is Root) name.compareTo(other.name) else 1 + + /** + * Create a string representation of this root node which prints its own [name]. + * + * @return A string representation of this node. + */ + override fun toString(): String = name + } + + /** + * A child in the hierarchy of [ActorPath]s. + */ + data class Child(override val parent: ActorPath, override val name: String) : ActorPath() { + init { + require(name.indexOf('/') == -1) { "/ may not exist in a path component" } + require(name.indexOf('#') == -1) { "# may not exist in a path component"} + } + + override val root: Root by lazy { + when (parent) { + is Root -> parent + else -> parent.root + } + } + + /** + * Compare the [specified][other] path with this child node for order. + * + * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater + * than the specified path. + */ + override fun compareTo(other: ActorPath): Int { + tailrec fun rec(left: ActorPath, right: ActorPath): Int = when { + left == right -> 0 + left is Root -> left.compareTo(right) + right is Root -> -(right.compareTo(left)) + else -> { + val x = left.name.compareTo(right.name) + if (x == 0) + rec(left.parent, right.parent) + else + x + } + } + return rec(this, other) + } + + /** + * Create a string representation of this child node which prints the name of [parent] and its own [name]. + * + * @return A string representation of this node. + */ + override fun toString(): String = "$parent/$name" + } +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt new file mode 100644 index 00000000..8d1e069c --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * A reference to an entity in simulation that accepts messages of type [T]. + */ +interface ActorRef<in T : Any> { + /** + * The path for this actor (from this actor up to the root actor). + */ + val path: ActorPath + + /** + * Send the specified message to the actor referenced by this [ActorRef]. + * + * @param msg The message to send to the referenced architecture. + * @param after The delay after which the message should be received by the actor. + */ + fun send(msg: T, after: Duration = 0.1) +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt new file mode 100644 index 00000000..a67f13d9 --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt @@ -0,0 +1,52 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * An actor system is a hierarchical grouping of actors that represents a discrete event simulation. + * + * An implementation of this interface should be provided by an engine. See for example *odcsim-engine-omega*, + * which is the reference implementation of the *odcsim* API. + * + * @param T The shape of the messages the root actor in the system can receive. + */ +interface ActorSystem<in T : Any> : ActorRef<T> { + /** + * The current point in simulation time. + */ + val time: Instant + + /** + * The name of this engine instance, used to distinguish between multiple engines running within the same JVM. + */ + val name: String + + /** + * Run the actors until the specified point in simulation time. + * + * @param until The point until which the simulation should run. + */ + fun run(until: Duration = Duration.POSITIVE_INFINITY) +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt new file mode 100644 index 00000000..f59bc966 --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt @@ -0,0 +1,38 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * A factory for [ActorSystem] instances that allows users to dynamically load engine implementations. + */ +interface ActorSystemFactory { + /** + * Create an [ActorSystem] with the given root [Behavior] and the given name. + * + * @param root The behavior of the root actor. + * @param name The name of the engine instance. + */ + operator fun <T : Any> invoke(root: Behavior<T>, name: String): ActorSystem<T> +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Behavior.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Behavior.kt new file mode 100644 index 00000000..54b02341 --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Behavior.kt @@ -0,0 +1,44 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * The behavior of an actor defines how it reacts to the messages that it receives. + * The message may either be of the type that the actor declares and which is part of the [ActorRef] signature, + * or it may be a system [Signal] that expresses a lifecycle event of either this actor or one of its child actors. + * + * @param T The shape of the messages the behavior accepts. + */ +interface Behavior<T : Any> { + /** + * Process an incoming message and return the actor's next [Behavior]. + */ + fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> = this + + /** + * Process an incoming [Signal] and return the actor's next [Behavior]. + */ + fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> = this +} diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt new file mode 100644 index 00000000..635bf9ac --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt @@ -0,0 +1,41 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * System signals are notifications that are generated by the system and delivered to the actor behavior in a reliable + * fashion. + */ +interface Signal + +/** + * Lifecycle signal that is fired upon creation of the actor. This will be the first message that the actor receives. + */ +object PreStart : Signal + +/** + * Lifecycle signal that is fired after this actor and all its child actors (transitively) have terminated. + */ +object PostStop : Signal diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Time.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Time.kt new file mode 100644 index 00000000..8eab3bdc --- /dev/null +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Time.kt @@ -0,0 +1,35 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * An instantaneous point on the time-line, used to record message time-stamps in a simulation. + */ +typealias Instant = Double + +/** + * A time interval which represents the amount of elapsed time between two messages. + */ +typealias Duration = Double diff --git a/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemFactoryTest.kt b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemFactoryTest.kt new file mode 100644 index 00000000..a374548c --- /dev/null +++ b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemFactoryTest.kt @@ -0,0 +1,35 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +/** + * A conformance test suite for implementors of the [ActorSystemFactory] interface. + */ +abstract class ActorSystemFactoryTest { + /** + * Create an [ActorSystemFactory] instance to test. + */ + abstract fun createFactory(): ActorSystemFactory +} diff --git a/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemTest.kt b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemTest.kt new file mode 100644 index 00000000..62df356b --- /dev/null +++ b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemTest.kt @@ -0,0 +1,101 @@ +/* + * MIT License + * + * Copyright (c) 2018 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.odcsim + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Assumptions.assumeTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.lang.IllegalArgumentException + +const val DELTA: Double = 0.0001 + +/** + * A conformance test suite for implementors of the [ActorSystem] interface. + */ +abstract class ActorSystemTest { + /** + * An [ActorSystemFactory] provided by implementors to create the [ActorSystem] to be tested. + */ + abstract val factory: ActorSystemFactory + + /** + * Test whether the created [ActorSystem] has the correct name. + */ + @Test + fun `should have a name`() { + val name = "test" + val system = factory(object : Behavior<Unit> {}, name) + + assertEquals(name, system.name) + } + + /** + * Test whether creating an [ActorSystem] sets the initial time at 0. + */ + @Test + fun `should start at t=0`() { + val system = factory(object : Behavior<Unit> {}, name = "test") + + assertTrue(Math.abs(system.time) < DELTA) + } + + /** + * Test whether an [ActorSystem] does not accept invalid points in time. + */ + @Test + fun `should not accept negative instants for running`() { + val system = factory(object : Behavior<Unit> {}, name = "test") + assertThrows<IllegalArgumentException> { system.run(-10.0) } + } + + /** + * Test whether an [ActorSystem] will not jump backward in time when asking to run until a specified instant + * that has already occurred. + */ + @Test + fun `should not jump backward in time`() { + val until = 10.0 + val system = factory(object : Behavior<Unit> {}, name = "test") + + system.run(until = until) + system.run(until = until - 0.5) + assertTrue(Math.abs(system.time - until) < DELTA) + } + + /** + * Test whether an [ActorSystem] will jump forward in time when asking to run until a specified instant. + */ + @Test + fun `should jump forward in time`() { + val until = 10.0 + val system = factory(object : Behavior<Unit> {}, name = "test") + + assumeTrue(Math.abs(system.time) < DELTA) + system.run(until = until) + assertTrue(Math.abs(system.time - until) < DELTA) + } +} |
