Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding JVM SpecInterceptor reclassifying aborted tests as Ignored #3268

Merged
merged 3 commits into from Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,10 @@
package io.kotest.engine

import io.kotest.common.KotestInternal
import io.kotest.engine.spec.interceptor.SpecInterceptor

/**
* Returns the [SpecInterceptor]s that should be used for this platform.
*/
@KotestInternal
internal expect fun specInterceptorsForPlatform(): List<SpecInterceptor>
Expand Up @@ -31,6 +31,7 @@ import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.engine.spec.interceptor.SpecStartedInterceptor
import io.kotest.engine.spec.interceptor.SystemPropertySpecFilterInterceptor
import io.kotest.engine.spec.interceptor.TagsExcludedSpecInterceptor
import io.kotest.engine.specInterceptorsForPlatform
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName
import kotlin.reflect.KClass
Expand Down Expand Up @@ -98,7 +99,7 @@ class SpecExecutor(
ProjectContextInterceptor(context.toProjectContext()),
SpecExtensionInterceptor(context.configuration.registry),
ConfigurationInContextInterceptor(context.configuration),
)
) + specInterceptorsForPlatform()

val initial: suspend (Spec) -> Result<Map<TestCase, TestResult>> = {
try {
Expand Down
Expand Up @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor
import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()
Expand Up @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor
import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()
Expand Up @@ -4,6 +4,7 @@ import io.kotest.common.KotestInternal
import io.kotest.engine.interceptors.DumpConfigInterceptor
import io.kotest.engine.interceptors.EmptyTestSuiteInterceptor
import io.kotest.engine.interceptors.EngineInterceptor
import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor
import io.kotest.engine.interceptors.ProjectExtensionEngineInterceptor
import io.kotest.engine.interceptors.ProjectListenerEngineInterceptor
import io.kotest.engine.interceptors.ProjectTimeoutEngineInterceptor
Expand All @@ -12,6 +13,7 @@ import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.interceptors.WriteFailuresInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -28,3 +30,7 @@ actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf(MarkAbortedExceptionsAsSkippedTestInterceptor)
@@ -0,0 +1,34 @@
package io.kotest.engine.interceptors

import io.kotest.common.JVMOnly
import io.kotest.common.KotestInternal
import io.kotest.core.spec.Spec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.spec.interceptor.SpecInterceptor
import org.opentest4j.TestAbortedException

/**
* Writes failed specs to a file so that the [io.kotest.engine.spec.FailureFirstSorter]
* can use the file to run failed specs first.
*
* Note: This is a JVM only feature.
*/
@JVMOnly
internal object MarkAbortedExceptionsAsSkippedTestInterceptor : SpecInterceptor {

override suspend fun intercept(
spec: Spec,
fn: suspend (Spec) -> Result<Map<TestCase, TestResult>>
): Result<Map<TestCase, TestResult>> {
return fn(spec).map { success ->
success.mapValues { (_, result) ->
if (result.errorOrNull is TestAbortedException) {
TestResult.Ignored
} else {
result
}
}
}
}
}
@@ -0,0 +1,64 @@
package com.sksamuel.kotest.engine.interceptors

import io.kotest.core.descriptors.Descriptor
import io.kotest.core.descriptors.DescriptorId
import io.kotest.core.names.TestName
import io.kotest.core.spec.style.FreeSpec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.core.test.TestType
import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.result.shouldBeSuccess
import org.opentest4j.TestAbortedException
import kotlin.time.Duration.Companion.milliseconds

class AbortedExceptionTest : FreeSpec({

val fakeTestCase = TestCase(
Descriptor.TestDescriptor(
Descriptor.SpecDescriptor(DescriptorId("dummy"), DummySpec::class),
DescriptorId("test")
), TestName("dummy"), DummySpec(), {}, type = TestType.Test
)

"Test should be marked as Ignored" {
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Error(1.milliseconds, TestAbortedException()))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Ignored)
}

"Failure is not reclassified" {
val assertionError = AssertionError("blah")
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Failure(1.milliseconds, assertionError))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Failure(1.milliseconds, assertionError))
}

"Successful test is not reclassified" {
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Success(1.milliseconds))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Success(1.milliseconds))
}
})

private class DummySpec : FreeSpec()