Gradle, Native: run tests with proper Test task, process test results
#KT-30529 Fixed
This commit is contained in:
+1
-1
@@ -608,7 +608,7 @@ abstract class BaseGradleIT {
|
||||
val testReportDir = projectDir.resolve("build/test-results/$testReportName")
|
||||
|
||||
if (!testReportDir.isDirectory) {
|
||||
error("Test report dir was not created")
|
||||
error("Test report dir $testReportDir was not created")
|
||||
}
|
||||
|
||||
val actualTestResults = readAndCleanupTestResults(testReportDir, projectDir)
|
||||
|
||||
+3
-2
@@ -1075,7 +1075,7 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
@Test
|
||||
fun testNativeTests() = with(Project("new-mpp-native-tests", gradleVersion)) {
|
||||
val testTasks = listOf("macos64Test", "linux64Test", "mingw64Test")
|
||||
val hostTestTask = ":${nativeHostTargetName}Test"
|
||||
val hostTestTask = "${nativeHostTargetName}Test"
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
println(output)
|
||||
@@ -1086,7 +1086,8 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
build("check") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(hostTestTask)
|
||||
assertTasksExecuted(":$hostTestTask")
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", hostTestTask)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@
|
||||
<testsuite name="CommonTest" tests="3" skipped="1" failures="2" errors="0" timestamp="..." hostname="..." time="...">
|
||||
<properties />
|
||||
<testcase name="test1" classname="CommonTest" time="...">
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.targets.js.NodeJsTestFailure">...</failure>
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.testing.KotlinTestFailure">...</failure>
|
||||
</testcase>
|
||||
<testcase name="test2" classname="CommonTest" time="...">
|
||||
<skipped />
|
||||
</testcase>
|
||||
<testcase name="test3" classname="CommonTest" time="...">
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.targets.js.NodeJsTestFailure">...</failure>
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.testing.KotlinTestFailure">...</failure>
|
||||
</testcase>
|
||||
<system-out />
|
||||
<system-err />
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<skipped />
|
||||
</testcase>
|
||||
<testcase name="test3" classname="CommonTest" time="...">
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.targets.js.NodeJsTestFailure">...</failure>
|
||||
<failure message="..." type="org.jetbrains.kotlin.gradle.testing.KotlinTestFailure">...</failure>
|
||||
</testcase>
|
||||
<system-out />
|
||||
<system-err />
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<testsuite name="org.foo.test.TestKt" tests="2" skipped="0" failures="0" errors="0" timestamp="..." hostname="..." time="...">
|
||||
<properties/>
|
||||
<testcase name="fooTest" classname="org.foo.test.TestKt" time="..."/>
|
||||
<testcase name="barTest" classname="org.foo.test.TestKt" time="..."/>
|
||||
<system-out/>
|
||||
<system-err/>
|
||||
</testsuite>
|
||||
</results>
|
||||
+68
-37
@@ -2,23 +2,25 @@ package org.jetbrains.kotlin.gradle.internal.testing
|
||||
|
||||
import jetbrains.buildServer.messages.serviceMessages.*
|
||||
import org.gradle.api.internal.tasks.testing.*
|
||||
import org.gradle.api.tasks.testing.TestOutputEvent
|
||||
import org.gradle.api.tasks.testing.TestOutputEvent.Destination.StdErr
|
||||
import org.gradle.api.tasks.testing.TestOutputEvent.Destination.StdOut
|
||||
import org.gradle.api.tasks.testing.TestResult
|
||||
import org.gradle.api.tasks.testing.TestResult.ResultType.*
|
||||
import org.gradle.internal.operations.OperationIdentifier
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.targets.js.NodeJsTestFailure
|
||||
import org.jetbrains.kotlin.gradle.testing.KotlinTestFailure
|
||||
import org.slf4j.Logger
|
||||
import java.text.ParseException
|
||||
import java.lang.System.currentTimeMillis as currentTimeMillis1
|
||||
|
||||
data class TCServiceMessagesClientSettings(
|
||||
val rootNodeName: String,
|
||||
val nameOfRootSuiteToAppend: String? = null,
|
||||
val nameOfRootSuiteToReplace: String? = null,
|
||||
val nameOfLeafTestToAppend: String? = null,
|
||||
val skipRoots: Boolean = false
|
||||
val rootNodeName: String,
|
||||
val nameOfRootSuiteToAppend: String? = null,
|
||||
val nameOfRootSuiteToReplace: String? = null,
|
||||
val nameOfLeafTestToAppend: String? = null,
|
||||
val skipRoots: Boolean = false,
|
||||
val treatFailedTestOutputAsStacktrace: Boolean = false
|
||||
) {
|
||||
init {
|
||||
if (skipRoots) {
|
||||
@@ -29,9 +31,9 @@ data class TCServiceMessagesClientSettings(
|
||||
}
|
||||
|
||||
internal class TCServiceMessagesClient(
|
||||
private val results: TestResultProcessor,
|
||||
val settings: TCServiceMessagesClientSettings,
|
||||
val log: Logger
|
||||
private val results: TestResultProcessor,
|
||||
val settings: TCServiceMessagesClientSettings,
|
||||
val log: Logger
|
||||
) : ServiceMessageParserCallback {
|
||||
inline fun root(operation: OperationIdentifier, actions: () -> Unit) {
|
||||
RootNode(operation.id).open { root ->
|
||||
@@ -55,8 +57,8 @@ internal class TCServiceMessagesClient(
|
||||
when (message) {
|
||||
is TestSuiteStarted -> open(message.ts, SuiteNode(leaf, hookSuiteName(leaf, message.suiteName)))
|
||||
is TestStarted -> beginTest(message.ts, message.testName)
|
||||
is TestStdOut -> results.output(requireLeafTest().descriptor, DefaultTestOutputEvent(StdOut, message.stdOut))
|
||||
is TestStdErr -> results.output(requireLeafTest().descriptor, DefaultTestOutputEvent(StdErr, message.stdErr))
|
||||
is TestStdOut -> requireLeafTest().output(StdOut, message.stdOut)
|
||||
is TestStdErr -> requireLeafTest().output(StdErr, message.stdErr)
|
||||
is TestFailed -> requireLeafTest().failure(message)
|
||||
is TestFinished -> endTest(message.ts, message.testName)
|
||||
is TestIgnored -> {
|
||||
@@ -74,17 +76,18 @@ internal class TCServiceMessagesClient(
|
||||
}
|
||||
|
||||
private fun hookSuiteName(parent: Node?, originalName: String) =
|
||||
if (parent?.parent == null && settings.nameOfRootSuiteToReplace != null) settings.nameOfRootSuiteToReplace
|
||||
else originalName
|
||||
if (parent?.parent == null && settings.nameOfRootSuiteToReplace != null) settings.nameOfRootSuiteToReplace
|
||||
else originalName
|
||||
|
||||
override fun regularText(text: String) {
|
||||
log.kotlinDebug { "TCSM stdout captured: $text" }
|
||||
val actualText = text + "\n"
|
||||
|
||||
val test = leaf as? TestNode
|
||||
if (test != null) {
|
||||
results.output(test.descriptor, DefaultTestOutputEvent(StdOut, text))
|
||||
test.output(StdOut, actualText)
|
||||
} else {
|
||||
println(text)
|
||||
print(actualText)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,19 +98,23 @@ internal class TCServiceMessagesClient(
|
||||
|
||||
if (settings.nameOfLeafTestToAppend != null) {
|
||||
val group = open(ts, SuiteNode(parent, parsedName.methodName))
|
||||
open(ts, TestNode(
|
||||
open(
|
||||
ts, TestNode(
|
||||
group, parsedName.className, parsedName.classDisplayName, parsedName.methodName,
|
||||
displayName = "${parsedName.methodName}.${settings.nameOfLeafTestToAppend}",
|
||||
localId = "$testName.${settings.nameOfLeafTestToAppend}",
|
||||
ignored = isIgnored
|
||||
))
|
||||
)
|
||||
)
|
||||
} else {
|
||||
open(ts, TestNode(
|
||||
open(
|
||||
ts, TestNode(
|
||||
parent, parsedName.className, parsedName.classDisplayName, parsedName.methodName,
|
||||
displayName = parsedName.methodName,
|
||||
localId = testName,
|
||||
ignored = isIgnored
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,11 +129,32 @@ internal class TCServiceMessagesClient(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Node.failure(
|
||||
message: TestFailed
|
||||
private fun TestNode.failure(
|
||||
message: TestFailed
|
||||
) {
|
||||
hasFailures = true
|
||||
results.failure(descriptor.id, NodeJsTestFailure(message.messageName, message.stacktrace))
|
||||
|
||||
val stacktrace = buildString {
|
||||
append(message.stacktrace)
|
||||
|
||||
if (settings.treatFailedTestOutputAsStacktrace) {
|
||||
append(output)
|
||||
output.setLength(0)
|
||||
}
|
||||
}
|
||||
|
||||
results.failure(descriptor.id, KotlinTestFailure(message.failureMessage, stacktrace))
|
||||
}
|
||||
|
||||
private fun TestNode.output(
|
||||
destination: TestOutputEvent.Destination,
|
||||
text: String
|
||||
) {
|
||||
if (settings.treatFailedTestOutputAsStacktrace) {
|
||||
output.append(text)
|
||||
}
|
||||
|
||||
results.output(descriptor.id, DefaultTestOutputEvent(destination, text))
|
||||
}
|
||||
|
||||
private inline fun <NodeType : Node> NodeType.open(contents: (NodeType) -> Unit) = open(System.currentTimeMillis()) {
|
||||
@@ -154,7 +182,7 @@ internal class TCServiceMessagesClient(
|
||||
if (assertLocalId != null) {
|
||||
check(it.localId == assertLocalId) {
|
||||
"Bad TCSM: unexpected node to close: ${it.localId}, stack: ${
|
||||
collectParents().joinToString("") { item -> "\n - ${item.localId}" }
|
||||
collectParents().joinToString("") { item -> "\n - ${item.localId}" }
|
||||
}\n"
|
||||
}
|
||||
}
|
||||
@@ -203,8 +231,8 @@ internal class TCServiceMessagesClient(
|
||||
* Node of tests tree
|
||||
*/
|
||||
abstract inner class Node(
|
||||
var parent: Node? = null,
|
||||
val localId: String
|
||||
var parent: Node? = null,
|
||||
val localId: String
|
||||
) {
|
||||
val reportingParent: Node?
|
||||
get() = when {
|
||||
@@ -256,9 +284,9 @@ internal class TCServiceMessagesClient(
|
||||
|
||||
inner class RootNode(val ownerBuildOperationId: Any) : Node(null, settings.rootNodeName) {
|
||||
override val descriptor =
|
||||
object : DefaultTestSuiteDescriptor(settings.rootNodeName, localId) {
|
||||
override fun getOwnerBuildOperationId(): Any? = this@RootNode.ownerBuildOperationId
|
||||
}
|
||||
object : DefaultTestSuiteDescriptor(settings.rootNodeName, localId) {
|
||||
override fun getOwnerBuildOperationId(): Any? = this@RootNode.ownerBuildOperationId
|
||||
}
|
||||
}
|
||||
|
||||
inner class SuiteNode(parent: Node? = null, name: String) : Node(parent, name) {
|
||||
@@ -268,14 +296,16 @@ internal class TCServiceMessagesClient(
|
||||
}
|
||||
|
||||
inner class TestNode(
|
||||
parent: Node,
|
||||
className: String,
|
||||
classDisplayName: String,
|
||||
methodName: String,
|
||||
displayName: String,
|
||||
localId: String,
|
||||
ignored: Boolean = false
|
||||
parent: Node,
|
||||
className: String,
|
||||
classDisplayName: String,
|
||||
methodName: String,
|
||||
displayName: String,
|
||||
localId: String,
|
||||
ignored: Boolean = false
|
||||
) : Node(parent, localId) {
|
||||
val output by lazy { StringBuilder() }
|
||||
|
||||
override val descriptor = object : DefaultTestDescriptor(id, className, methodName, classDisplayName, displayName) {
|
||||
override fun getParent(): TestDescriptorInternal? = this@TestNode.parent?.descriptor
|
||||
}
|
||||
@@ -303,8 +333,9 @@ internal class TCServiceMessagesClient(
|
||||
|
||||
private fun requireLeaf() = leaf ?: error("test out of group")
|
||||
private fun requireLeafGroup() = requireLeaf().also {
|
||||
check(it !is TestNode) { "previous test `$it` not finished"}
|
||||
check(it !is TestNode) { "previous test `$it` not finished" }
|
||||
}
|
||||
|
||||
private fun requireLeafTest() = leaf as? TestNode
|
||||
?: error("no running test")
|
||||
?: error("no running test")
|
||||
}
|
||||
+7
-6
@@ -14,9 +14,10 @@ import java.io.PipedOutputStream
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
data class TCServiceMessagesTestExecutionSpec(
|
||||
val forkOptions: ProcessForkOptions,
|
||||
val args: List<String>,
|
||||
val clientSettings: TCServiceMessagesClientSettings
|
||||
val forkOptions: ProcessForkOptions,
|
||||
val args: List<String>,
|
||||
val checkExitCode: Boolean,
|
||||
val clientSettings: TCServiceMessagesClientSettings
|
||||
) : TestExecutionSpec
|
||||
|
||||
private val log = LoggerFactory.getLogger("org.jetbrains.kotlin.gradle.tasks.testing")
|
||||
@@ -50,8 +51,8 @@ class TCServiceMessagesTestExecutor(
|
||||
ServiceMessage.parse(it, client)
|
||||
} catch (e: Exception) {
|
||||
log.error(
|
||||
"Error while processing test process output message \"$it\"",
|
||||
e
|
||||
"Error while processing test process output message \"$it\"",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -73,7 +74,7 @@ class TCServiceMessagesTestExecutor(
|
||||
val result = execHandle!!.waitForFinish()
|
||||
outputReaderThread!!.join()
|
||||
|
||||
if (result.exitValue != 0) {
|
||||
if (spec.checkExitCode && result.exitValue != 0) {
|
||||
error("$execHandle exited with errors (exit code: ${result.exitValue})")
|
||||
}
|
||||
}
|
||||
|
||||
+5
-17
@@ -3,7 +3,7 @@ package org.jetbrains.kotlin.gradle.targets.js
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.plugins.JavaBasePlugin
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.testing.base.plugins.TestingBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExtension
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsSetupTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTestTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
@@ -48,14 +49,6 @@ internal class KotlinJsCompilationTestsConfigurator(
|
||||
private val nodeModulesDir
|
||||
get() = project.buildDir.resolve(disambiguateUnderscored("node_modules", true))
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private val Project.testResults: File
|
||||
get() = project.buildDir.resolve(TestingBasePlugin.TEST_RESULTS_DIR_NAME)
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private val Project.testReports: File
|
||||
get() = project.buildDir.resolve(TestingBasePlugin.TESTS_DIR_NAME)
|
||||
|
||||
private val compileTask: Kotlin2JsCompile
|
||||
get() = project.tasks.findByName(compileTestKotlin2Js.name) as Kotlin2JsCompile
|
||||
|
||||
@@ -85,7 +78,7 @@ internal class KotlinJsCompilationTestsConfigurator(
|
||||
val projectWithNodeJsPlugin = NodeJsPlugin.ensureAppliedInHierarchy(target.project)
|
||||
|
||||
val testTask = registerTask(project, testTaskName, KotlinNodeJsTestTask::class.java) { testJs ->
|
||||
testJs.group = "verification"
|
||||
testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
|
||||
testJs.dependsOn(nodeModulesTask.getTaskOrProvider())
|
||||
|
||||
@@ -106,16 +99,11 @@ internal class KotlinJsCompilationTestsConfigurator(
|
||||
)
|
||||
testJs.nodeModulesToLoad = setOf(compileTestKotlin2Js.outputFile.name)
|
||||
|
||||
val htmlReport = DslObject(testJs.reports.html)
|
||||
val xmlReport = DslObject(testJs.reports.junitXml)
|
||||
|
||||
xmlReport.conventionMapping.map("destination") { project.testResults.resolve(testJs.name) }
|
||||
htmlReport.conventionMapping.map("destination") { project.testReports.resolve(testJs.name) }
|
||||
testJs.conventionMapping.map("binResultsDir") { project.testResults.resolve(testJs.name + "/binary") }
|
||||
KotlinTestTask.configureConventions(testJs)
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
project.tasks.findByName(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(testTask.getTaskOrProvider())
|
||||
project.tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(testTask.getTaskOrProvider())
|
||||
|
||||
// defer nodeJs executable setup, as nodejs project settings may change during configuration
|
||||
testTask.configure {
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
/**
|
||||
* Class to be shown in default Gradle tests console reporter.
|
||||
*
|
||||
* Example console output:
|
||||
* ```
|
||||
* clientTest.CommonTest.test1 FAILED
|
||||
* org.jetbrains.kotlin.gradle.targets.js.NodeJsTestFailure
|
||||
* ```
|
||||
*/
|
||||
class NodeJsTestFailure(message: String, val stackTrace: String?) : Throwable(message) {
|
||||
override fun fillInStackTrace(): Throwable = this
|
||||
override fun toString(): String = stackTrace ?: ""
|
||||
}
|
||||
+14
-46
@@ -5,38 +5,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.tasks
|
||||
|
||||
import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.testing.AbstractTestTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.process.ProcessForkOptions
|
||||
import org.gradle.process.internal.DefaultProcessForkOptions
|
||||
import org.gradle.process.internal.ExecHandleFactory
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTestTask
|
||||
import org.jetbrains.kotlin.gradle.testing.IgnoredTestSuites
|
||||
import org.jetbrains.kotlin.gradle.testing.TestsGrouping
|
||||
import org.jetbrains.kotlin.gradle.utils.injected
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
open class KotlinNodeJsTestTask : AbstractTestTask() {
|
||||
open class KotlinNodeJsTestTask : KotlinTestTask() {
|
||||
@Input
|
||||
var ignoredTestSuites: IgnoredTestSuites =
|
||||
IgnoredTestSuites.showWithContents
|
||||
|
||||
@Input
|
||||
var testsGrouping: TestsGrouping =
|
||||
TestsGrouping.root
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
var targetName: String? = null
|
||||
|
||||
@Input
|
||||
var excludes = mutableSetOf<String>()
|
||||
|
||||
@InputDirectory
|
||||
lateinit var nodeModulesDir: File
|
||||
|
||||
@@ -47,25 +33,15 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
|
||||
@Input
|
||||
lateinit var testRuntimeNodeModules: Collection<String>
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private val filterExt: DefaultTestFilter
|
||||
get() = filter as DefaultTestFilter
|
||||
|
||||
init {
|
||||
filterExt.isFailOnNoMatchingTests = false
|
||||
}
|
||||
|
||||
@get:Inject
|
||||
open val fileResolver: FileResolver
|
||||
get() = injected
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@Internal
|
||||
val nodeJsProcessOptions: ProcessForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
|
||||
@Suppress("unused")
|
||||
val nodeJsExecutable: String
|
||||
@Input get() = nodeJsProcessOptions.executable
|
||||
|
||||
@Suppress("unused")
|
||||
val nodeJsWorkingDirCanonicalPath: String
|
||||
@Input get() = nodeJsProcessOptions.workingDir.canonicalPath
|
||||
|
||||
@@ -108,23 +84,15 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
|
||||
return TCServiceMessagesTestExecutionSpec(
|
||||
extendedForkOptions,
|
||||
nodeJsArgs +
|
||||
testRuntimeNodeModules
|
||||
.map { nodeModulesDir.resolve(it) }
|
||||
.filter { it.exists() }
|
||||
.map { it.absolutePath } +
|
||||
cliArgs.toList(),
|
||||
testRuntimeNodeModules
|
||||
.map { nodeModulesDir.resolve(it) }
|
||||
.filter { it.exists() }
|
||||
.map { it.absolutePath } +
|
||||
cliArgs.toList(),
|
||||
true,
|
||||
clientSettings
|
||||
)
|
||||
}
|
||||
|
||||
@get:Inject
|
||||
open val execHandleFactory: ExecHandleFactory
|
||||
get() = injected
|
||||
|
||||
override fun createTestExecuter() = TCServiceMessagesTestExecutor(
|
||||
execHandleFactory,
|
||||
buildOperationExecutor
|
||||
)
|
||||
}
|
||||
|
||||
data class KotlinNodeJsTestRunnerCliArgs(
|
||||
|
||||
+31
-20
@@ -14,18 +14,19 @@ import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||
import org.gradle.api.internal.artifacts.ArtifactAttributes
|
||||
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
|
||||
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.reporting.ReportingExtension
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.testing.base.plugins.TestingBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTestTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@@ -127,27 +128,37 @@ open class KotlinNativeTargetConfigurator(
|
||||
|
||||
private fun Project.createRunTask(binary: Executable) {
|
||||
val taskName = binary.runTaskName ?: return
|
||||
// TODO provide a special exec task for tests.
|
||||
tasks.create(taskName, Exec::class.java).apply {
|
||||
if (binary.isDefaultTestExecutable) {
|
||||
|
||||
if (binary.isDefaultTestExecutable) {
|
||||
tasks.create(taskName, KotlinNativeTestTask::class.java).apply {
|
||||
tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(this)
|
||||
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
description = "Executes Kotlin/Native unit tests for target ${binary.target.name}."
|
||||
tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(this)
|
||||
if (project.hasProperty("teamcity.version")) {
|
||||
args("--ktest_logger=TEAMCITY")
|
||||
}
|
||||
} else {
|
||||
|
||||
enabled = binary.target.konanTarget.isCurrentHost
|
||||
|
||||
executable = binary.outputFile
|
||||
workingDir = project.projectDir.absolutePath
|
||||
|
||||
onlyIf { binary.outputFile.exists() }
|
||||
dependsOn(binary.linkTaskName)
|
||||
|
||||
KotlinTestTask.configureConventions(this)
|
||||
}
|
||||
} else {
|
||||
tasks.create(taskName, Exec::class.java).apply {
|
||||
group = RUN_GROUP
|
||||
description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
|
||||
|
||||
enabled = binary.target.konanTarget.isCurrentHost
|
||||
|
||||
executable = binary.outputFile.absolutePath
|
||||
workingDir = project.projectDir
|
||||
|
||||
onlyIf { binary.outputFile.exists() }
|
||||
dependsOn(binary.linkTaskName)
|
||||
}
|
||||
|
||||
enabled = binary.target.konanTarget.isCurrentHost
|
||||
|
||||
executable = binary.outputFile.absolutePath
|
||||
workingDir = project.projectDir
|
||||
|
||||
onlyIf { binary.outputFile.exists() }
|
||||
dependsOn(binary.linkTaskName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.process.ProcessForkOptions
|
||||
import org.gradle.process.internal.DefaultProcessForkOptions
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTestTask
|
||||
import org.jetbrains.kotlin.gradle.testing.TestsGrouping
|
||||
import java.io.File
|
||||
|
||||
open class KotlinNativeTestTask : KotlinTestTask() {
|
||||
@Suppress("LeakingThis")
|
||||
@Internal
|
||||
val processOptions: ProcessForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
|
||||
var executable: File
|
||||
@InputFile
|
||||
@SkipWhenEmpty
|
||||
get() = File(processOptions.executable)
|
||||
set(value) {
|
||||
processOptions.executable = value.absolutePath
|
||||
}
|
||||
|
||||
var workingDir: String
|
||||
@Input get() = processOptions.workingDir.canonicalPath
|
||||
set(value) {
|
||||
processOptions.workingDir = File(value)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun processOptions(options: ProcessForkOptions.() -> Unit) {
|
||||
options(processOptions)
|
||||
}
|
||||
|
||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||
val extendedForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
processOptions.copyTo(extendedForkOptions)
|
||||
|
||||
val clientSettings = when (testsGrouping) {
|
||||
TestsGrouping.none -> TCServiceMessagesClientSettings(rootNodeName = name)
|
||||
TestsGrouping.root -> TCServiceMessagesClientSettings(rootNodeName = name, nameOfRootSuiteToAppend = targetName)
|
||||
TestsGrouping.leaf -> TCServiceMessagesClientSettings(rootNodeName = name, nameOfLeafTestToAppend = targetName)
|
||||
}.copy(treatFailedTestOutputAsStacktrace = true)
|
||||
|
||||
val cliArgs = CliArgs("TEAMCITY", includePatterns, excludePatterns)
|
||||
|
||||
return TCServiceMessagesTestExecutionSpec(
|
||||
extendedForkOptions,
|
||||
cliArgs.toList(),
|
||||
false,
|
||||
clientSettings
|
||||
)
|
||||
}
|
||||
|
||||
private class CliArgs(
|
||||
val testLogger: String? = null,
|
||||
val testGradleFilter: Set<String> = setOf(),
|
||||
val testNegativeGradleFilter: Set<String> = setOf()
|
||||
) {
|
||||
fun toList() = mutableListOf<String>().also {
|
||||
if (testLogger != null) {
|
||||
it.add("--ktest_logger=$testLogger")
|
||||
}
|
||||
|
||||
if (testGradleFilter.isNotEmpty()) {
|
||||
it.add("--ktest_gradle_filter=${testGradleFilter.joinToString(",")}")
|
||||
}
|
||||
|
||||
if (testNegativeGradleFilter.isNotEmpty()) {
|
||||
it.add("--ktest_negative_gradle_filter=${testNegativeGradleFilter.joinToString(",")}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter
|
||||
import org.gradle.api.reporting.ReportingExtension
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.testing.AbstractTestTask
|
||||
import org.gradle.process.internal.ExecHandleFactory
|
||||
import org.gradle.testing.base.plugins.TestingBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor
|
||||
import org.jetbrains.kotlin.gradle.testing.TestsGrouping
|
||||
import org.jetbrains.kotlin.gradle.utils.injected
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class KotlinTestTask : AbstractTestTask() {
|
||||
@Input
|
||||
var testsGrouping: TestsGrouping =
|
||||
TestsGrouping.root
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
var targetName: String? = null
|
||||
|
||||
@Input
|
||||
var excludes = mutableSetOf<String>()
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
protected val filterExt: DefaultTestFilter
|
||||
@Internal get() = filter as DefaultTestFilter
|
||||
|
||||
init {
|
||||
filterExt.isFailOnNoMatchingTests = false
|
||||
}
|
||||
|
||||
protected val includePatterns: Set<String>
|
||||
@Internal get() = filterExt.includePatterns + filterExt.commandLineIncludePatterns
|
||||
|
||||
protected val excludePatterns: Set<String>
|
||||
@Internal get() = excludes
|
||||
|
||||
@get:Inject
|
||||
open val fileResolver: FileResolver
|
||||
get() = injected
|
||||
|
||||
@get:Inject
|
||||
open val execHandleFactory: ExecHandleFactory
|
||||
get() = injected
|
||||
|
||||
override fun createTestExecuter() = TCServiceMessagesTestExecutor(
|
||||
execHandleFactory,
|
||||
buildOperationExecutor
|
||||
)
|
||||
|
||||
companion object {
|
||||
@Suppress("UnstableApiUsage")
|
||||
private val Project.testResults: File
|
||||
get() = project.buildDir.resolve(TestingBasePlugin.TEST_RESULTS_DIR_NAME)
|
||||
|
||||
private val Project.reportsDir: File
|
||||
get() = project.extensions.getByType(ReportingExtension::class.java).baseDir
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private val Project.testReports: File
|
||||
get() = reportsDir.resolve(TestingBasePlugin.TESTS_DIR_NAME)
|
||||
|
||||
internal fun configureConventions(task: KotlinTestTask) {
|
||||
val htmlReport = DslObject(task.reports.html)
|
||||
val xmlReport = DslObject(task.reports.junitXml)
|
||||
|
||||
xmlReport.conventionMapping.map("destination") { task.project.testResults.resolve(task.name) }
|
||||
htmlReport.conventionMapping.map("destination") { task.project.testReports.resolve(task.name) }
|
||||
task.conventionMapping.map("binResultsDir") { task.project.testResults.resolve(task.name + "/binary") }
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.testing
|
||||
|
||||
/**
|
||||
* Class to be shown in default Gradle tests console reporter.
|
||||
*
|
||||
* Example console output:
|
||||
* ```
|
||||
* clientTest.CommonTest.test1 FAILED
|
||||
* org.jetbrains.kotlin.gradle.testing.KotlinTestFailure
|
||||
* ```
|
||||
*/
|
||||
class KotlinTestFailure(message: String?, private val stackTrace: String?) : Throwable(message) {
|
||||
override fun fillInStackTrace(): Throwable = this
|
||||
override fun toString(): String =
|
||||
if (stackTrace != null) {
|
||||
if (message != null && message !in stackTrace) message + "\n" + stackTrace
|
||||
else stackTrace
|
||||
} else message ?: "Test failed"
|
||||
}
|
||||
+1
-1
@@ -30,7 +30,7 @@ class RecordingTestResultProcessor : TestResultProcessor {
|
||||
}
|
||||
|
||||
override fun failure(testId: Any, result: Throwable) {
|
||||
line("FAILURE ${result.message} // $testId")
|
||||
line("FAILURE $result // $testId")
|
||||
}
|
||||
|
||||
override fun completed(testId: Any, event: TestCompleteEvent) {
|
||||
|
||||
+17
-13
@@ -4,19 +4,20 @@ import jetbrains.buildServer.messages.serviceMessages.*
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClient
|
||||
import org.junit.Test
|
||||
|
||||
class Complex: TCServiceMessagesClientTest() {
|
||||
class Complex : TCServiceMessagesClientTest() {
|
||||
@Test
|
||||
fun testComplexJs() {
|
||||
nameOfRootSuiteToReplace = "js"
|
||||
|
||||
assertEvents("""
|
||||
assertEvents(
|
||||
"""
|
||||
STARTED SUITE root // root
|
||||
STARTED SUITE js // root.js
|
||||
STARTED SUITE MyTest // root.js.MyTest
|
||||
STARTED TEST displayName: myTest1, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest1 // root.js.MyTest.my.company.product.MyTest.myTest1
|
||||
COMPLETED SUCCESS // root.js.MyTest.my.company.product.MyTest.myTest1
|
||||
STARTED TEST displayName: myTest2, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest2 // root.js.MyTest.my.company.product.MyTest.myTest2
|
||||
FAILURE testFailed // root.js.MyTest.my.company.product.MyTest.myTest2
|
||||
FAILURE null // root.js.MyTest.my.company.product.MyTest.myTest2
|
||||
COMPLETED FAILURE // root.js.MyTest.my.company.product.MyTest.myTest2
|
||||
STARTED TEST displayName: myTest3, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest3 // root.js.MyTest.my.company.product.MyTest.myTest3
|
||||
COMPLETED SKIPPED // root.js.MyTest.my.company.product.MyTest.myTest3
|
||||
@@ -24,7 +25,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest4, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest4 // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest4
|
||||
COMPLETED SUCCESS // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest4
|
||||
STARTED TEST displayName: myTest5, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest5 // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
FAILURE testFailed // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
FAILURE null // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
COMPLETED FAILURE // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
STARTED TEST displayName: myTest6, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest6 // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest6
|
||||
COMPLETED SKIPPED // root.js.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest6
|
||||
@@ -32,7 +33,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest7, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest7 // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest7
|
||||
COMPLETED SUCCESS // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest7
|
||||
STARTED TEST displayName: myTest8, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest8 // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
FAILURE testFailed // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
FAILURE null // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
COMPLETED FAILURE // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
STARTED TEST displayName: myTest9, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest9 // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest9
|
||||
COMPLETED SKIPPED // root.js.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest9
|
||||
@@ -43,7 +44,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest10, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest10 // root.js.MyTest2.my.company.product.MyTest2.myTest10
|
||||
COMPLETED SUCCESS // root.js.MyTest2.my.company.product.MyTest2.myTest10
|
||||
STARTED TEST displayName: myTest11, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest11 // root.js.MyTest2.my.company.product.MyTest2.myTest11
|
||||
FAILURE testFailed // root.js.MyTest2.my.company.product.MyTest2.myTest11
|
||||
FAILURE null // root.js.MyTest2.my.company.product.MyTest2.myTest11
|
||||
COMPLETED FAILURE // root.js.MyTest2.my.company.product.MyTest2.myTest11
|
||||
STARTED TEST displayName: myTest12, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest12 // root.js.MyTest2.my.company.product.MyTest2.myTest12
|
||||
COMPLETED SKIPPED // root.js.MyTest2.my.company.product.MyTest2.myTest12
|
||||
@@ -66,7 +67,8 @@ STARTED SUITE root // root
|
||||
COMPLETED FAILURE // root.js.MyTest2
|
||||
COMPLETED FAILURE // root.js
|
||||
COMPLETED FAILURE // root
|
||||
""") {
|
||||
"""
|
||||
) {
|
||||
serviceMessage(TestSuiteStarted(""))
|
||||
complexFixture()
|
||||
serviceMessage(TestSuiteFinished(""))
|
||||
@@ -77,14 +79,15 @@ COMPLETED FAILURE // root
|
||||
fun testComplexIos() {
|
||||
nameOfRootSuiteToAppend = "ios"
|
||||
|
||||
assertEvents("""
|
||||
assertEvents(
|
||||
"""
|
||||
STARTED SUITE root // root
|
||||
STARTED SUITE ios // root.ios
|
||||
STARTED SUITE MyTest // root.ios.MyTest
|
||||
STARTED TEST displayName: myTest1, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest1 // root.ios.MyTest.my.company.product.MyTest.myTest1
|
||||
COMPLETED SUCCESS // root.ios.MyTest.my.company.product.MyTest.myTest1
|
||||
STARTED TEST displayName: myTest2, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest2 // root.ios.MyTest.my.company.product.MyTest.myTest2
|
||||
FAILURE testFailed // root.ios.MyTest.my.company.product.MyTest.myTest2
|
||||
FAILURE null // root.ios.MyTest.my.company.product.MyTest.myTest2
|
||||
COMPLETED FAILURE // root.ios.MyTest.my.company.product.MyTest.myTest2
|
||||
STARTED TEST displayName: myTest3, classDisplayName: MyTest, className: my.company.product.MyTest, name: myTest3 // root.ios.MyTest.my.company.product.MyTest.myTest3
|
||||
COMPLETED SKIPPED // root.ios.MyTest.my.company.product.MyTest.myTest3
|
||||
@@ -92,7 +95,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest4, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest4 // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest4
|
||||
COMPLETED SUCCESS // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest4
|
||||
STARTED TEST displayName: myTest5, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest5 // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
FAILURE testFailed // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
FAILURE null // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
COMPLETED FAILURE // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest5
|
||||
STARTED TEST displayName: myTest6, classDisplayName: MyTestNested, className: my.company.product.MyTest.MyTestNested, name: myTest6 // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest6
|
||||
COMPLETED SKIPPED // root.ios.MyTest.MyTestNested.my.company.product.MyTest.MyTestNested.myTest6
|
||||
@@ -100,7 +103,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest7, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest7 // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest7
|
||||
COMPLETED SUCCESS // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest7
|
||||
STARTED TEST displayName: myTest8, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest8 // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
FAILURE testFailed // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
FAILURE null // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
COMPLETED FAILURE // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest8
|
||||
STARTED TEST displayName: myTest9, classDisplayName: MyTestNestedNested, className: my.company.product.MyTest.MyTestNestedNested, name: myTest9 // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest9
|
||||
COMPLETED SKIPPED // root.ios.MyTest.MyTestNested.MyTestNestedNested.my.company.product.MyTest.MyTestNestedNested.myTest9
|
||||
@@ -111,7 +114,7 @@ STARTED SUITE root // root
|
||||
STARTED TEST displayName: myTest10, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest10 // root.ios.MyTest2.my.company.product.MyTest2.myTest10
|
||||
COMPLETED SUCCESS // root.ios.MyTest2.my.company.product.MyTest2.myTest10
|
||||
STARTED TEST displayName: myTest11, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest11 // root.ios.MyTest2.my.company.product.MyTest2.myTest11
|
||||
FAILURE testFailed // root.ios.MyTest2.my.company.product.MyTest2.myTest11
|
||||
FAILURE null // root.ios.MyTest2.my.company.product.MyTest2.myTest11
|
||||
COMPLETED FAILURE // root.ios.MyTest2.my.company.product.MyTest2.myTest11
|
||||
STARTED TEST displayName: myTest12, classDisplayName: MyTest2, className: my.company.product.MyTest2, name: myTest12 // root.ios.MyTest2.my.company.product.MyTest2.myTest12
|
||||
COMPLETED SKIPPED // root.ios.MyTest2.my.company.product.MyTest2.myTest12
|
||||
@@ -134,7 +137,8 @@ STARTED SUITE root // root
|
||||
COMPLETED FAILURE // root.ios.MyTest2
|
||||
COMPLETED FAILURE // root.ios
|
||||
COMPLETED FAILURE // root
|
||||
""") {
|
||||
"""
|
||||
) {
|
||||
complexFixture()
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.kotlin.gradle.internal.testing.tcsmc
|
||||
|
||||
import jetbrains.buildServer.messages.serviceMessages.ServiceMessage
|
||||
import org.gradle.internal.operations.OperationIdentifier
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.RecordingTestResultProcessor
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClient
|
||||
@@ -13,6 +14,7 @@ open class TCServiceMessagesClientTest {
|
||||
protected var nameOfRootSuiteToReplace: String? = null
|
||||
protected var nameOfLeafTestToAppend: String? = null
|
||||
protected var skipRoots: Boolean = false
|
||||
protected var treatFailedTestOutputAsStacktrace: Boolean = false
|
||||
|
||||
internal fun assertEvents(assertion: String, produceServiceMessage: TCServiceMessagesClient.() -> Unit) {
|
||||
val results = RecordingTestResultProcessor()
|
||||
@@ -36,9 +38,13 @@ open class TCServiceMessagesClientTest {
|
||||
nameOfRootSuiteToAppend,
|
||||
nameOfRootSuiteToReplace,
|
||||
nameOfLeafTestToAppend,
|
||||
skipRoots
|
||||
skipRoots,
|
||||
treatFailedTestOutputAsStacktrace
|
||||
),
|
||||
LoggerFactory.getLogger("test")
|
||||
)
|
||||
}
|
||||
|
||||
internal fun TCServiceMessagesClient.serviceMessage(name: String, attributes: Map<String, String>) =
|
||||
serviceMessage(ServiceMessage.parse(ServiceMessage.asString(name, attributes))!!)
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.internal.testing.tcsmc
|
||||
|
||||
import jetbrains.buildServer.messages.serviceMessages.TestFinished
|
||||
import jetbrains.buildServer.messages.serviceMessages.TestStarted
|
||||
import jetbrains.buildServer.messages.serviceMessages.TestSuiteFinished
|
||||
import jetbrains.buildServer.messages.serviceMessages.TestSuiteStarted
|
||||
import org.junit.Test
|
||||
|
||||
class TestFailureTest : TCServiceMessagesClientTest() {
|
||||
@Test
|
||||
fun testJs() {
|
||||
assertEvents(
|
||||
"""
|
||||
STARTED SUITE root // root
|
||||
STARTED SUITE // root.
|
||||
STARTED TEST displayName: Test, classDisplayName: , className: , name: Test // root..Test
|
||||
FAILURE AssertionError: Expected value to be true.
|
||||
at AssertionError_init_0 (mpplib2/build/tmp/expandedArchives/kotlin-stdlib-js-1.3-SNAPSHOT.jar_730a1b227513cf16a9b639e009a985fc/kotlin/exceptions.kt:102:37)
|
||||
at DefaultJsAsserter.failWithMessage_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:80:19)
|
||||
at DefaultJsAsserter.assertTrue_o10pc4${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:60:13)
|
||||
at DefaultJsAsserter.assertTrue_4mavae${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:67:9)
|
||||
at assertTrue_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/Assertions.kt:36:21)
|
||||
at SampleTestsJS.testHello (mpplib2/src/jsTest/kotlin/sample/SampleTestsJS.kt:9:9)
|
||||
at mpplib2/build/js_test_node_modules/mpplib2_test.js:59:38
|
||||
at Object.fn [as test] (mpplib2/build/tmp/expandedArchives/src/KotlinTestRunner.ts:12:25)
|
||||
at Object.test (mpplib2/build/tmp/expandedArchives/src/KotlinTestTeamCityReporter.ts:80:28)
|
||||
at test (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/TestApi.kt:57:15) // root..Test
|
||||
COMPLETED FAILURE // root..Test
|
||||
COMPLETED FAILURE // root.
|
||||
COMPLETED FAILURE // root
|
||||
"""
|
||||
) {
|
||||
serviceMessage(TestSuiteStarted(""))
|
||||
serviceMessage(TestStarted("Test", false, null))
|
||||
serviceMessage(
|
||||
"testFailed",
|
||||
mapOf(
|
||||
"name" to "Test",
|
||||
"message" to "Expected value to be true",
|
||||
"details" to """AssertionError: Expected value to be true.
|
||||
at AssertionError_init_0 (mpplib2/build/tmp/expandedArchives/kotlin-stdlib-js-1.3-SNAPSHOT.jar_730a1b227513cf16a9b639e009a985fc/kotlin/exceptions.kt:102:37)
|
||||
at DefaultJsAsserter.failWithMessage_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:80:19)
|
||||
at DefaultJsAsserter.assertTrue_o10pc4$ (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:60:13)
|
||||
at DefaultJsAsserter.assertTrue_4mavae$ (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:67:9)
|
||||
at assertTrue_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/Assertions.kt:36:21)
|
||||
at SampleTestsJS.testHello (mpplib2/src/jsTest/kotlin/sample/SampleTestsJS.kt:9:9)
|
||||
at mpplib2/build/js_test_node_modules/mpplib2_test.js:59:38
|
||||
at Object.fn [as test] (mpplib2/build/tmp/expandedArchives/src/KotlinTestRunner.ts:12:25)
|
||||
at Object.test (mpplib2/build/tmp/expandedArchives/src/KotlinTestTeamCityReporter.ts:80:28)
|
||||
at test (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/TestApi.kt:57:15)"""
|
||||
)
|
||||
)
|
||||
serviceMessage(TestFinished("Test", 0))
|
||||
serviceMessage(TestSuiteFinished(""))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNative() {
|
||||
treatFailedTestOutputAsStacktrace = true
|
||||
|
||||
assertEvents(
|
||||
"""
|
||||
STARTED SUITE root // root
|
||||
STARTED SUITE // root.
|
||||
STARTED TEST displayName: Test, classDisplayName: , className: , name: Test // root..Test
|
||||
StdOut[AssertionError: Expected value to be true.
|
||||
at AssertionError_init_0 (mpplib2/build/tmp/expandedArchives/kotlin-stdlib-js-1.3-SNAPSHOT.jar_730a1b227513cf16a9b639e009a985fc/kotlin/exceptions.kt:102:37)
|
||||
at DefaultJsAsserter.failWithMessage_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:80:19)
|
||||
at DefaultJsAsserter.assertTrue_o10pc4${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:60:13)
|
||||
at DefaultJsAsserter.assertTrue_4mavae${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:67:9)
|
||||
at assertTrue_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/Assertions.kt:36:21)
|
||||
at SampleTestsJS.testHello (mpplib2/src/jsTest/kotlin/sample/SampleTestsJS.kt:9:9)
|
||||
at mpplib2/build/js_test_node_modules/mpplib2_test.js:59:38
|
||||
at Object.fn [as test] (mpplib2/build/tmp/expandedArchives/src/KotlinTestRunner.ts:12:25)
|
||||
at Object.test (mpplib2/build/tmp/expandedArchives/src/KotlinTestTeamCityReporter.ts:80:28)
|
||||
at test (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/TestApi.kt:57:15)
|
||||
] // root..Test
|
||||
FAILURE Expected <7>, actual <42>
|
||||
nullAssertionError: Expected value to be true.
|
||||
at AssertionError_init_0 (mpplib2/build/tmp/expandedArchives/kotlin-stdlib-js-1.3-SNAPSHOT.jar_730a1b227513cf16a9b639e009a985fc/kotlin/exceptions.kt:102:37)
|
||||
at DefaultJsAsserter.failWithMessage_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:80:19)
|
||||
at DefaultJsAsserter.assertTrue_o10pc4${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:60:13)
|
||||
at DefaultJsAsserter.assertTrue_4mavae${'$'} (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:67:9)
|
||||
at assertTrue_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/Assertions.kt:36:21)
|
||||
at SampleTestsJS.testHello (mpplib2/src/jsTest/kotlin/sample/SampleTestsJS.kt:9:9)
|
||||
at mpplib2/build/js_test_node_modules/mpplib2_test.js:59:38
|
||||
at Object.fn [as test] (mpplib2/build/tmp/expandedArchives/src/KotlinTestRunner.ts:12:25)
|
||||
at Object.test (mpplib2/build/tmp/expandedArchives/src/KotlinTestTeamCityReporter.ts:80:28)
|
||||
at test (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/TestApi.kt:57:15)
|
||||
// root..Test
|
||||
COMPLETED FAILURE // root..Test
|
||||
COMPLETED FAILURE // root.
|
||||
COMPLETED FAILURE // root
|
||||
"""
|
||||
) {
|
||||
serviceMessage(TestSuiteStarted(""))
|
||||
serviceMessage(TestStarted("Test", false, null))
|
||||
regularText(
|
||||
"""AssertionError: Expected value to be true.
|
||||
at AssertionError_init_0 (mpplib2/build/tmp/expandedArchives/kotlin-stdlib-js-1.3-SNAPSHOT.jar_730a1b227513cf16a9b639e009a985fc/kotlin/exceptions.kt:102:37)
|
||||
at DefaultJsAsserter.failWithMessage_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:80:19)
|
||||
at DefaultJsAsserter.assertTrue_o10pc4$ (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:60:13)
|
||||
at DefaultJsAsserter.assertTrue_4mavae$ (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/DefaultJsAsserter.kt:67:9)
|
||||
at assertTrue_0 (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/Assertions.kt:36:21)
|
||||
at SampleTestsJS.testHello (mpplib2/src/jsTest/kotlin/sample/SampleTestsJS.kt:9:9)
|
||||
at mpplib2/build/js_test_node_modules/mpplib2_test.js:59:38
|
||||
at Object.fn [as test] (mpplib2/build/tmp/expandedArchives/src/KotlinTestRunner.ts:12:25)
|
||||
at Object.test (mpplib2/build/tmp/expandedArchives/src/KotlinTestTeamCityReporter.ts:80:28)
|
||||
at test (mpplib2/build/tmp/expandedArchives/kotlin-test-js-1.3-SNAPSHOT.jar_d60f1e6d0dd94843a03bf98a569bbb73/src/main/kotlin/kotlin/test/TestApi.kt:57:15)"""
|
||||
)
|
||||
serviceMessage(
|
||||
"testFailed",
|
||||
mapOf(
|
||||
"name" to "Test",
|
||||
"message" to "Expected <7>, actual <42>"
|
||||
)
|
||||
)
|
||||
serviceMessage(TestFinished("Test", 0))
|
||||
serviceMessage(TestSuiteFinished(""))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user