summaryrefslogtreecommitdiff
path: root/odcsim-core
diff options
context:
space:
mode:
Diffstat (limited to 'odcsim-core')
-rw-r--r--odcsim-core/build.gradle56
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt59
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt137
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt43
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt52
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt38
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/Behavior.kt44
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt41
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/Time.kt35
-rw-r--r--odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemFactoryTest.kt35
-rw-r--r--odcsim-core/src/test/kotlin/com/atlarge/odcsim/ActorSystemTest.kt101
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)
+ }
+}