Gradle, Native: run tests with proper Test task, process test results

#KT-30529 Fixed
This commit is contained in:
Sergey Rostov
2019-04-02 13:01:32 +03:00
parent d5e434e95b
commit bdac47369c
18 changed files with 487 additions and 162 deletions
@@ -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)
@@ -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)
}
}
@@ -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 />
@@ -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 />
@@ -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>
@@ -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")
}
@@ -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})")
}
}
@@ -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 {
@@ -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 ?: ""
}
@@ -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(
@@ -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)
}
}
@@ -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(",")}")
}
}
}
}
@@ -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") }
}
}
}
@@ -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"
}
@@ -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) {
@@ -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()
}
}
@@ -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))!!)
}
@@ -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(""))
}
}
}