summaryrefslogtreecommitdiff
path: root/opendc-harness
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-05-04 20:31:48 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-05-05 10:03:18 +0200
commit6466d5e1b8da4582434f02dff2ab56e8f736ef85 (patch)
treee8c8e6b96c7abdd80fa0a3198da5776488cd06fe /opendc-harness
parent4a8b32d288ba3ee986ecef7933fa77554d34e762 (diff)
harness: Extend Harness CLI with classpath options
This change adds support for appending libraries to the classpath when searching for experiments to run using the OpenDC Harness command line interface.
Diffstat (limited to 'opendc-harness')
-rw-r--r--opendc-harness/opendc-harness-cli/build.gradle.kts6
-rw-r--r--opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt56
-rw-r--r--opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt6
-rw-r--r--opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt4
-rw-r--r--opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt3
-rw-r--r--opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt2
-rw-r--r--opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt2
-rw-r--r--opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt3
8 files changed, 68 insertions, 14 deletions
diff --git a/opendc-harness/opendc-harness-cli/build.gradle.kts b/opendc-harness/opendc-harness-cli/build.gradle.kts
index 26f02f55..3e169e2a 100644
--- a/opendc-harness/opendc-harness-cli/build.gradle.kts
+++ b/opendc-harness/opendc-harness-cli/build.gradle.kts
@@ -25,6 +25,12 @@ description = "Command line interface of OpenDC Harness"
/* Build configuration */
plugins {
`kotlin-library-conventions`
+ application
+}
+
+application {
+ applicationName = "opendc-harness"
+ mainClass.set("org.opendc.harness.runner.cli.ConsoleRunnerKt")
}
dependencies {
diff --git a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt
index c59e623c..82adb2fd 100644
--- a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt
+++ b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt
@@ -23,16 +23,23 @@
package org.opendc.harness.runner.cli
import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.parameters.arguments.argument
+import com.github.ajalt.clikt.parameters.arguments.multiple
+import com.github.ajalt.clikt.parameters.arguments.unique
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.multiple
import com.github.ajalt.clikt.parameters.options.option
+import com.github.ajalt.clikt.parameters.options.unique
+import com.github.ajalt.clikt.parameters.types.file
import com.github.ajalt.clikt.parameters.types.int
import mu.KotlinLogging
+import org.junit.platform.commons.util.ClassLoaderUtils
import org.opendc.harness.engine.ExperimentEngineLauncher
import org.opendc.harness.engine.discovery.DiscoveryProvider
import org.opendc.harness.engine.discovery.DiscoveryRequest
import org.opendc.harness.engine.discovery.DiscoverySelector
import org.opendc.harness.engine.scheduler.ThreadPoolExperimentScheduler
+import java.net.URLClassLoader
/**
* The logger for this experiment runner.
@@ -53,23 +60,38 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") {
/**
* The selected experiments to run by name.
*/
- private val experiments by option("-e", "--experiments", help = "Names of experiments to explore")
- .multiple(emptyList())
+ private val experiments by argument(help = "Experiments to explore")
+ .multiple()
+ .unique()
/**
* The maximum number of worker threads to use.
*/
private val parallelism by option("-p", "--parallelism", help = "Maximum number of concurrent simulation runs")
.int()
- .default(Runtime.getRuntime().availableProcessors())
+ .default(Runtime.getRuntime().availableProcessors() - 1)
+
+ /**
+ * Additional classpath entries to load.
+ */
+ private val additionalClasspathEntries by option("--class-path", help = "Additional classpath entries to load")
+ .file(mustExist = true)
+ .multiple()
+ .unique()
override fun run() {
logger.info { "Starting OpenDC Console Experiment Runner" }
- val discovery = DiscoveryProvider.createComposite()
+ val classLoader = createClassLoader()
+ // TODO: Add way to specify class loader for scheduler
+ Thread.currentThread().contextClassLoader = classLoader
+
+ val discovery = DiscoveryProvider.createComposite(classLoader)
val experiments = discovery.discover(
DiscoveryRequest(
- selectors = experiments.map { DiscoverySelector.Name(it) }
+ selectors = experiments.flatMap {
+ listOf(DiscoverySelector.Name(it), DiscoverySelector.Meta("class.name", it))
+ }
)
)
@@ -91,6 +113,30 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") {
logger.info { "Finished all experiments. Exiting." }
}
+
+ /**
+ * Create a [ClassLoader] that is used to load the
+ */
+ private fun createClassLoader(): ClassLoader {
+ val parent = ClassLoaderUtils.getDefaultClassLoader()
+
+ if (additionalClasspathEntries.isNotEmpty()) {
+ val urls = additionalClasspathEntries.flatMap { file ->
+ if (file.isDirectory) {
+ file.walk()
+ .filter { it.extension == "jar" }
+ .map { it.toURI().toURL() }
+ .toList()
+ } else {
+ listOf(file.toURI().toURL())
+ }
+ }
+
+ return URLClassLoader.newInstance(urls.toTypedArray(), parent)
+ }
+
+ return parent
+ }
}
/**
diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt
index 204de3fc..c4b420c5 100644
--- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt
+++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt
@@ -40,7 +40,7 @@ public interface DiscoveryProvider {
/**
* Factory method for creating a new [Discovery] instance.
*/
- public fun create(): Discovery
+ public fun create(classLoader: ClassLoader): Discovery
public companion object {
/**
@@ -58,8 +58,8 @@ public interface DiscoveryProvider {
/**
* Obtain a composite [Discovery] that combines the results of all available providers.
*/
- public fun createComposite(): Discovery {
- return CompositeDiscovery(providers)
+ public fun createComposite(classLoader: ClassLoader): Discovery {
+ return CompositeDiscovery(classLoader, providers)
}
}
}
diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt
index 8ebc485a..726125a8 100644
--- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt
+++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt
@@ -32,11 +32,11 @@ import org.opendc.harness.engine.discovery.DiscoveryRequest
/**
* A composite [Discovery] instance that combines the results of multiple delegate instances.
*/
-internal class CompositeDiscovery(providers: Iterable<DiscoveryProvider>) : Discovery {
+internal class CompositeDiscovery(classLoader: ClassLoader, providers: Iterable<DiscoveryProvider>) : Discovery {
/**
* The [Discovery] instances to delegate to.
*/
- private val delegates = providers.map { it.create() }
+ private val delegates = providers.map { it.create(classLoader) }
@OptIn(FlowPreview::class)
override fun discover(request: DiscoveryRequest): Flow<ExperimentDefinition> {
diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt
index 20708230..3fa3fe35 100644
--- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt
+++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt
@@ -36,7 +36,7 @@ import org.opendc.harness.engine.discovery.DiscoverySelector
/**
* A [Discovery] implementation that discovers [Experiment] instances on the classpath.
*/
-internal class DslDiscovery : Discovery {
+internal class DslDiscovery(private val classLoader: ClassLoader) : Discovery {
/*
* Lazily memoize the results of the classpath scan.
*/
@@ -84,6 +84,7 @@ internal class DslDiscovery : Discovery {
*/
private fun scan(): ScanResult {
return ClassGraph()
+ .addClassLoader(classLoader)
.enableClassInfo()
.enableExternalClasses()
.ignoreClassVisibility()
diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt
index 987bc889..6a9bd599 100644
--- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt
+++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt
@@ -32,5 +32,5 @@ import org.opendc.harness.engine.discovery.DiscoveryProvider
public class DslDiscoveryProvider : DiscoveryProvider {
override val id: String = "dsl"
- override fun create(): Discovery = DslDiscovery()
+ override fun create(classLoader: ClassLoader): Discovery = DslDiscovery(classLoader)
}
diff --git a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt
index 6f2989db..6955f7c5 100644
--- a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt
+++ b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt
@@ -50,7 +50,7 @@ internal class EngineTest {
@Test
fun discovery() {
runBlocking {
- val discovery = DiscoveryProvider.findById("dsl")?.create()
+ val discovery = DiscoveryProvider.findById("dsl")?.create(Thread.currentThread().contextClassLoader)
assertNotNull(discovery)
val res = mutableListOf<ExperimentDefinition>()
discovery?.discover(DiscoveryRequest())?.toList(res)
diff --git a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt
index ab7367b8..7fc97f6d 100644
--- a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt
+++ b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt
@@ -25,6 +25,7 @@ package org.opendc.harness.runner.junit5
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import mu.KotlinLogging
+import org.junit.platform.commons.util.ClassLoaderUtils
import org.junit.platform.engine.*
import org.junit.platform.engine.discovery.ClassNameFilter
import org.junit.platform.engine.discovery.ClassSelector
@@ -63,7 +64,7 @@ public class OpenDCTestEngine : TestEngine {
val classNames = request.getSelectorsByType(ClassSelector::class.java).map { DiscoverySelector.Meta("class.name", it.className) }
val classNameFilters = request.getFiltersByType(ClassNameFilter::class.java).map { DiscoveryFilter.Name(it.toPredicate()) }
- val discovery = DiscoveryProvider.createComposite()
+ val discovery = DiscoveryProvider.createComposite(ClassLoaderUtils.getDefaultClassLoader())
val definitions = discovery.discover(DiscoveryRequest(classNames, classNameFilters))
return ExperimentEngineDescriptor(uniqueId, definitions)