diff --git a/.github/workflows/check-pr-core.yaml b/.github/workflows/check-pr-core.yaml index f26be50a1..10db1d56e 100644 --- a/.github/workflows/check-pr-core.yaml +++ b/.github/workflows/check-pr-core.yaml @@ -16,6 +16,13 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] + include: + - os: ubuntu-latest + task: spekLinuxTest spekJvmTest + - os: macos-latest + task: spekMacosTest spekJvmTest + - os: windows-latest + task: spekWindowsTest spekJvmTest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 @@ -31,7 +38,7 @@ jobs: - uses: eskatos/gradle-command-action@v1 with: build-root-directory: integration-test - arguments: check -PexcludeIdePlugins + arguments: ${{ matrix.task }} -PexcludeIdePlugins -i runner_junit5: runs-on: ubuntu-latest steps: diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ac3a3456a..916971c64 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -12,8 +12,8 @@ repositories { } dependencies { - api(kotlin("gradle-plugin", version = "1.4-M3")) - api("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17") + api(kotlin("gradle-plugin", version = "1.4.0-rc")) + api("org.jetbrains.dokka:dokka-gradle-plugin:1.4.0-rc") api("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") api("gradle.plugin.org.jetbrains.intellij.plugins:gradle-intellij-plugin:0.4.10") api("com.github.jengelman.gradle.plugins:shadow:4.0.2") diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index b8a89a5b5..607dff739 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -16,7 +16,7 @@ object Dependencies { val mockitoCore = "org.mockito:mockito-core:2.23.4" val mockitoInline = "org.mockito:mockito-inline:2.23.4" - val kotlinCoroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7-1.4-M3" + val kotlinCoroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8-1.4.0-rc" val autoService = "com.google.auto.service:auto-service:1.0-rc4" } diff --git a/gradle.properties b/gradle.properties index 74ce827a9..85770b678 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ -kotlin.mpp.enableGranularSourceSetsMetadata=true +# This causes problems with composite builds! +# kotlin.mpp.enableGranularSourceSetsMetadata=true org.gradle.jvmArgs=-Xmx3G \ No newline at end of file diff --git a/integration-test/build.gradle.kts b/integration-test/build.gradle.kts index c74d6d5c9..6c216f1e2 100644 --- a/integration-test/build.gradle.kts +++ b/integration-test/build.gradle.kts @@ -10,38 +10,29 @@ repositories { } kotlin { - metadata {} jvm {} + js {} linuxX64("linux") {} macosX64("macos") {} mingwX64("windows") {} sourceSets { - val commonMain by getting { - dependencies { - implementation(kotlin("stdlib")) - } - } + val commonMain by getting val commonTest by getting { dependencies { implementation("org.spekframework.spek2:spek-dsl") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8-1.4.0-rc") implementation("org.spekframework.spek2:spek-runtime") implementation(kotlin("test")) } } jvm { - compilations["main"].defaultSourceSet { - dependencies { - implementation(kotlin("stdlib-jdk8")) - } - } - compilations["test"].defaultSourceSet { dependencies { runtimeOnly(kotlin("reflect")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7-1.4-M3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8-1.4.0-rc") implementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.0.0") implementation("org.mockito:mockito-core:2.23.4") runtimeOnly("org.spekframework.spek2:spek-runner-junit5") @@ -112,7 +103,8 @@ spek2 { tasks { afterEvaluate { val runSpekJvmTest by getting(Test::class) { - systemProperty("spek2.discovery.concurrent", "") + systemProperty("spek2.discovery.parallel.enabled", "") + systemProperty("spek2.execution.parallel.enabled", "") filter { includeTestsMatching("org.spekframework.spek2.*") } diff --git a/integration-test/buildSrc/build.gradle.kts b/integration-test/buildSrc/build.gradle.kts index fe00d929d..3e6d70b25 100644 --- a/integration-test/buildSrc/build.gradle.kts +++ b/integration-test/buildSrc/build.gradle.kts @@ -5,5 +5,5 @@ repositories { } dependencies { - implementation(kotlin("gradle-plugin", version = "1.4-M3")) + implementation(kotlin("gradle-plugin", version = "1.4.0-rc")) } \ No newline at end of file diff --git a/integration-test/gradle.properties b/integration-test/gradle.properties index 659b74c01..dce9c2baf 100644 --- a/integration-test/gradle.properties +++ b/integration-test/gradle.properties @@ -1 +1,3 @@ +# This causes problems with composite builds! +# kotlin.mpp.enableGranularSourceSetsMetadata=true org.gradle.jvmargs=-Xmx3G \ No newline at end of file diff --git a/integration-test/settings.gradle.kts b/integration-test/settings.gradle.kts index e711b7b04..c3110dce8 100644 --- a/integration-test/settings.gradle.kts +++ b/integration-test/settings.gradle.kts @@ -1,18 +1,8 @@ includeBuild("../") { dependencySubstitution { - substitute(module("org.spekframework.spek2:spek-gradle-plugin:0.1.0")).with(project(":spek-gradle-plugin")) + substitute(module("org.spekframework.spek2:spek-gradle-plugin")).with(project(":spek-gradle-plugin")) substitute(module("org.spekframework.spek2:spek-dsl")).with(project(":spek-dsl")) - substitute(module("org.spekframework.spek2:spek-dsl-metadata")).with(project(":spek-dsl")) - substitute(module("org.spekframework.spek2:spek-dsl-jvm")).with(project(":spek-dsl")) - substitute(module("org.spekframework.spek2:spek-dsl-linux")).with(project(":spek-dsl")) - substitute(module("org.spekframework.spek2:spek-dsl-windows")).with(project(":spek-dsl")) - substitute(module("org.spekframework.spek2:spek-dsl-macos")).with(project(":spek-dsl")) substitute(module("org.spekframework.spek2:spek-runtime")).with(project(":spek-runtime")) - substitute(module("org.spekframework.spek2:spek-runtime-metadata")).with(project(":spek-runtime")) - substitute(module("org.spekframework.spek2:spek-runtime-jvm")).with(project(":spek-runtime")) - substitute(module("org.spekframework.spek2:spek-runtime-linux")).with(project(":spek-runtime")) - substitute(module("org.spekframework.spek2:spek-runtime-windows")).with(project(":spek-runtime")) - substitute(module("org.spekframework.spek2:spek-runtime-macos")).with(project(":spek-runtime")) substitute(module("org.spekframework.spek2:spek-runner-junit5")).with(project(":spek-runner-junit5")) substitute(module("org.spekframework.spek2:spek-kotlin-compiler-plugin-jvm")).with(project(":spek-kotlin-compiler-plugin-jvm")) substitute(module("org.spekframework.spek2:spek-kotlin-compiler-plugin-native")).with(project(":spek-kotlin-compiler-plugin-native")) diff --git a/integration-test/src/commonTest/kotlin/org/spekframework/spek2/TestSupport.kt b/integration-test/src/commonTest/kotlin/org/spekframework/spek2/TestSupport.kt index 8780073cf..8cbc6be01 100644 --- a/integration-test/src/commonTest/kotlin/org/spekframework/spek2/TestSupport.kt +++ b/integration-test/src/commonTest/kotlin/org/spekframework/spek2/TestSupport.kt @@ -121,7 +121,7 @@ class SpekTestHelper { val runtime = SpekRuntime() val recorder = ExecutionRecorder() - val discoveryResult = runtime.discover(DiscoveryRequest(context, listOf(*paths))) + val discoveryResult = runtime.discoverAsync(DiscoveryRequest(context, listOf(*paths))) runtime.executeAsync(ExecutionRequest(discoveryResult.roots, recorder)) return recorder diff --git a/spek-dsl/build.gradle.kts b/spek-dsl/build.gradle.kts index bf0cf9899..15f10f33c 100644 --- a/spek-dsl/build.gradle.kts +++ b/spek-dsl/build.gradle.kts @@ -69,27 +69,6 @@ kotlin { } } } - - sourceSets { - val commonMain by getting { - dependencies { - implementation(kotlin("stdlib-common")) - api(Dependencies.kotlinCoroutinesCore) - } - } - - val jvmMain by getting { - dependencies { - implementation(kotlin("stdlib-jdk8")) - } - } - - val jsMain by getting { - dependencies { - implementation(kotlin("stdlib-js")) - } - } - } } val stubJavaDocJar by tasks.registering(Jar::class) { diff --git a/spek-runtime/build.gradle.kts b/spek-runtime/build.gradle.kts index 407db779f..55061f5f0 100644 --- a/spek-runtime/build.gradle.kts +++ b/spek-runtime/build.gradle.kts @@ -27,6 +27,17 @@ kotlin { } + js { + mavenPublication { + groupId = "org.spekframework.spek2" + artifactId = "spek-runtime-js" + pom { + name.set("Spek Runtime JS") + description.set("Kotlin JS module for spek-runtime") + } + } + } + linuxX64("linux") { mavenPublication { groupId = "org.spekframework.spek2" @@ -64,7 +75,6 @@ kotlin { val commonMain by getting { dependencies { api(project(":spek-dsl")) - implementation(kotlin("stdlib-common")) implementation(Dependencies.kotlinCoroutinesCore) } } @@ -72,7 +82,6 @@ kotlin { jvm { compilations["main"].defaultSourceSet { dependencies { - implementation(kotlin("stdlib-jdk8")) implementation(kotlin("reflect")) implementation(Dependencies.classgraph) } diff --git a/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/Executor.kt b/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/Executor.kt index df125286d..379000cd0 100644 --- a/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/Executor.kt +++ b/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/Executor.kt @@ -1,7 +1,6 @@ package org.spekframework.spek2.runtime import kotlinx.coroutines.* -import kotlinx.coroutines.withTimeoutOrNull import org.spekframework.spek2.dsl.Skip import org.spekframework.spek2.runtime.execution.ExecutionListener import org.spekframework.spek2.runtime.execution.ExecutionRequest @@ -15,7 +14,17 @@ import kotlin.coroutines.EmptyCoroutineContext class Executor { suspend fun execute(request: ExecutionRequest) { request.executionListener.executionStart() - request.roots.forEach { execute(it, request.executionListener) } + // note that this call will be run in parallel depending on the CoroutineDispatcher used + supervisorScope { + request.roots.map { async { execute(it, request.executionListener) } } + .forEach { job -> + try { + job.await() + } catch (e: Throwable) { + e.printStackTrace() + } + } + } request.executionListener.executionFinish() } diff --git a/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/SpekRuntime.kt b/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/SpekRuntime.kt index 0229cd61d..0055aad80 100644 --- a/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/SpekRuntime.kt +++ b/spek-runtime/src/commonMain/kotlin/org/spekframework/spek2/runtime/SpekRuntime.kt @@ -41,31 +41,39 @@ class SpekRuntime { } } + suspend fun discoverAsync(discoveryRequest: DiscoveryRequest): DiscoveryResult { + val scopes = mutableListOf() + coroutineScope { + filterScopes(discoveryRequest).collect { scope -> + scopes.add(scope) + } + } + + return DiscoveryResult(scopes) + } + @OptIn(ExperimentalTime::class) fun discover(discoveryRequest: DiscoveryRequest): DiscoveryResult { - val scopes = mutableListOf() - println("Spek discovery started.") + lateinit var results: DiscoveryResult + println("spek2: Discovery started.") val time = measureTime { doRunBlocking { - if (isConcurrentDiscoveryEnabled(false)) { + if (isParallelDiscoveryEnabled(false)) { + println("spek2: Running discovery phase in parallel.") withContext(Dispatchers.Default) { - filterScopes(discoveryRequest).collect { scope -> - scopes.add(scope) - } + results = discoverAsync(discoveryRequest) } } else { - filterScopes(discoveryRequest).collect { scope -> - scopes.add(scope) - } + results = discoverAsync(discoveryRequest) } } } - println("Spek discovery completed in ${time.inMilliseconds} ms") - return DiscoveryResult(scopes) + println("spek2: Discovery completed in ${time.inMilliseconds} ms") + return results } - + // For internal use only! suspend fun executeAsync(request: ExecutionRequest) { Executor().execute(request) } @@ -74,9 +82,16 @@ class SpekRuntime { fun execute(request: ExecutionRequest) { doRunBlocking { val job = coroutineScope { - // inherit the dispatcher from doRunBlocking (which is an event loop backed by the main thread) - launch { - executeAsync(request) + if (isParallelExecutionEnabled(false)) { + println("spek2: Running execution phase in parallel.") + launch(Dispatchers.Default) { + executeAsync(request) + } + } else { + // inherit the dispatcher from doRunBlocking (which is an event loop backed by the main thread) + launch { + executeAsync(request) + } } } @@ -121,5 +136,6 @@ class SpekRuntime { } } -expect fun isConcurrentDiscoveryEnabled(default: Boolean): Boolean +expect fun isParallelDiscoveryEnabled(default: Boolean): Boolean +expect fun isParallelExecutionEnabled(default: Boolean): Boolean expect fun getGlobalTimeoutSetting(default: Long): Long \ No newline at end of file diff --git a/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/JvmDiscoveryContextFactory.kt b/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/JvmDiscoveryContextFactory.kt index 958dfda78..c808dcf1b 100644 --- a/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/JvmDiscoveryContextFactory.kt +++ b/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/JvmDiscoveryContextFactory.kt @@ -10,7 +10,6 @@ import org.spekframework.spek2.runtime.discovery.DiscoveryContext import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.primaryConstructor -import kotlin.streams.toList object JvmDiscoveryContextFactory { // classgraph scan is already done in parallel, this property allows it to be overriden @@ -50,7 +49,6 @@ object JvmDiscoveryContextFactory { .enableClassInfo() // any jar on the classpath won't be scanned .disableJarScanning() - .verbose() if (testDirs.isNotEmpty()) { cg.overrideClasspath(System.getProperty("java.class.path"), *testDirs.toTypedArray()) @@ -66,7 +64,7 @@ object JvmDiscoveryContextFactory { } private fun filterScanResult(scanResult: ScanResult) : List> { - return scanResult.getSubclasses(Spek::class.qualifiedName!!).stream() + return scanResult.getSubclasses(Spek::class.qualifiedName!!) .map { it.loadClass() as Class } .filter { !it.isAnonymousClass } .map { it.kotlin } diff --git a/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/timeout.kt b/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/timeout.kt index 50c23ba93..15ce5bc06 100644 --- a/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/timeout.kt +++ b/spek-runtime/src/jvmMain/kotlin/org/spekframework/spek2/runtime/timeout.kt @@ -1,13 +1,14 @@ package org.spekframework.spek2.runtime actual fun getGlobalTimeoutSetting(default: Long): Long { - var override = System.getProperty("SPEK_TIMEOUT")?.toLong() - if (override == null) { - override = System.getProperty("spek2.timeout")?.toLong() - } + var override = System.getProperty("spek2.execution.test.timeout")?.toLong() return override ?: default } -actual fun isConcurrentDiscoveryEnabled(default: Boolean): Boolean { - return System.getProperty("spek2.discovery.concurrent") != null || default +actual fun isParallelDiscoveryEnabled(default: Boolean): Boolean { + return System.getProperty("spek2.discovery.parallel.enabled") != null || default +} + +actual fun isParallelExecutionEnabled(default: Boolean): Boolean { + return System.getProperty("spek2.execution.parallel.enabled") != null || default } \ No newline at end of file diff --git a/spek-runtime/src/nativeMain/kotlin/org/spekframework/spek2/runtime/timeout.kt b/spek-runtime/src/nativeMain/kotlin/org/spekframework/spek2/runtime/timeout.kt index 08a97ce53..ee63124c7 100644 --- a/spek-runtime/src/nativeMain/kotlin/org/spekframework/spek2/runtime/timeout.kt +++ b/spek-runtime/src/nativeMain/kotlin/org/spekframework/spek2/runtime/timeout.kt @@ -4,6 +4,10 @@ actual fun getGlobalTimeoutSetting(default: Long): Long { return default } -actual fun isConcurrentDiscoveryEnabled(default: Boolean): Boolean { +actual fun isParallelDiscoveryEnabled(default: Boolean): Boolean { + return default +} + +actual fun isParallelExecutionEnabled(default: Boolean): Boolean { return default } \ No newline at end of file