diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt index a07e05c9fc5..1ad02f8e4be 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt @@ -88,7 +88,7 @@ abstract class AbstractNativeKlibABITest : AbstractNativeSimpleTest() { ) val compilationResult = compilation.result.assertSuccess() // <-- trigger compilation - val executable = TestExecutable(executableFile, compilationResult.loggedData) + val executable = TestExecutable.fromCompilationResult(testCase, compilationResult) runExecutableAndVerify(testCase, executable) // <-- run executable and verify } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt index 10fe679c784..7f08faa5a6a 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt @@ -88,7 +88,7 @@ class InfrastructureDumpedTestListingTest : AbstractNativeSimpleTest() { assertTrue(dumpedTestListing.isNotEmpty()) // parse test listing obtained from executable file with the help of --ktest_list_tests flag: - val testExecutable = TestExecutable(executable.executableFile, executableCompilationResult.loggedData) + val testExecutable = TestExecutable.fromCompilationResult(executableTestCase, executableCompilationResult) val extractedTestListing = TestRunners.extractTestNames(testExecutable, testRunSettings).toSet() assertEquals(extractedTestListing, dumpedTestListing) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/LoggedData.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/LoggedData.kt index 4a8488bbde9..6fa9b70e174 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/LoggedData.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/LoggedData.kt @@ -28,9 +28,13 @@ internal abstract class LoggedData { protected abstract fun computeText(): String final override fun toString() = text - fun withErrorMessage(errorMessage: String): String = buildString { + fun withErrorMessage(errorMessage: String, t: Throwable? = null): String = buildString { appendLine(errorMessage) appendLine() + if (t != null) { + appendLine(t.stackTraceToString()) + appendLine() + } appendLine(this@LoggedData) } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRun.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRun.kt index 1e4f4ae5682..848145937ad 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRun.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRun.kt @@ -5,19 +5,50 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.runner -import org.jetbrains.kotlin.konan.blackboxtest.support.LoggedData -import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName -import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseId -import org.jetbrains.kotlin.konan.blackboxtest.support.TestName +import org.jetbrains.kotlin.konan.blackboxtest.support.* +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.Executable +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Success +import org.jetbrains.kotlin.konan.blackboxtest.support.util.DumpedTestListing import org.jetbrains.kotlin.konan.blackboxtest.support.util.startsWith import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertFalse +import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File +import java.io.IOException internal class TestExecutable( val executableFile: File, - val loggedCompilerCall: LoggedData.CompilerCall -) + val loggedCompilerCall: LoggedData.CompilerCall, + val testNames: Collection +) { + companion object { + fun fromCompilationResult(testCase: TestCase, compilationResult: Success): TestExecutable { + val testNames = when (testCase.kind) { + TestKind.REGULAR, TestKind.STANDALONE -> { + val testDumpFile = compilationResult.resultingArtifact.testDumpFile + val testDump = try { + testDumpFile.readText() + } catch (e: IOException) { + fail { compilationResult.loggedData.withErrorMessage("Failed to read test dump file: $testDumpFile", e) } + } + + try { + DumpedTestListing.parse(testDump) + } catch (e: Exception) { + fail { compilationResult.loggedData.withErrorMessage("Failed to parse test dump file: $testDumpFile", e) } + } + } + else -> emptyList() + } + + return TestExecutable( + executableFile = compilationResult.resultingArtifact.executableFile, + loggedCompilerCall = compilationResult.loggedData, + testNames = testNames + ) + } + } +} internal class TestRun( val displayName: String, diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRunProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRunProvider.kt index 443491d798d..d9fde23f893 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRunProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/runner/TestRunProvider.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilati import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationFactory import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProvider -import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestRunners.extractTestNames import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode @@ -34,7 +33,6 @@ internal class TestRunProvider( ) : BaseTestRunProvider(), ExtensionContext.Store.CloseableResource { private val compilationFactory = TestCompilationFactory() private val cachedCompilations = ThreadSafeCache>() - private val cachedTestNames = ThreadSafeCache>() /** * Produces a single [TestRun] per [TestCase]. So-called "one test case/one test run" mode. @@ -64,7 +62,7 @@ internal class TestRunProvider( fun getSingleTestRun( testCaseId: TestCaseId, settings: Settings - ): TestRun = withTestExecutable(testCaseId, settings) { testCase, executable, _ -> + ): TestRun = withTestExecutable(testCaseId, settings) { testCase, executable -> createSingleTestRun(testCase, executable) } @@ -101,7 +99,7 @@ internal class TestRunProvider( fun getTestRuns( testCaseId: TestCaseId, settings: Settings - ): Collection> = withTestExecutable(testCaseId, settings) { testCase, executable, cacheKey -> + ): Collection> = withTestExecutable(testCaseId, settings) { testCase, executable -> fun createTestRun(testRunName: String, testName: TestName?) = createTestRun(testCase, executable, testRunName, testName) when (testCase.kind) { @@ -111,10 +109,7 @@ internal class TestRunProvider( TreeNode.oneLevel(testRun) } TestKind.REGULAR, TestKind.STANDALONE -> { - val testNames = cachedTestNames.computeIfAbsent(cacheKey) { - extractTestNames(executable, settings) - }.filterIrrelevant(testCase) - + val testNames = executable.testNames.filterIrrelevant(testCase) testNames.buildTree(TestName::packageName) { testName -> createTestRun(testName.functionName, testName) } @@ -125,7 +120,7 @@ internal class TestRunProvider( private fun withTestExecutable( testCaseId: TestCaseId, settings: Settings, - action: (TestCase, TestExecutable, TestCompilationCacheKey) -> T + action: (TestCase, TestExecutable) -> T ): T { val testCaseGroup = testCaseGroupProvider.getTestCaseGroup(testCaseId.testCaseGroupId, settings) ?: fail { "No test case for $testCaseId" } @@ -134,32 +129,36 @@ internal class TestRunProvider( val testCase = testCaseGroup.getByName(testCaseId) ?: fail { "No test case for $testCaseId" } - val (testCompilation, cacheKey) = when (testCase.kind) { + val testCompilation = when (testCase.kind) { TestKind.STANDALONE, TestKind.STANDALONE_NO_TR -> { // Create a separate compilation for each standalone test case. - val cacheKey = TestCompilationCacheKey.Standalone(testCaseId) - val testCompilation = cachedCompilations.computeIfAbsent(cacheKey) { + cachedCompilations.computeIfAbsent( + TestCompilationCacheKey.Standalone(testCaseId) + ) { compilationFactory.testCasesToExecutable(listOf(testCase), settings) } - testCompilation to cacheKey } TestKind.REGULAR -> { // Group regular test cases by compiler arguments. val testRunnerType = testCase.extras().runnerType - val cacheKey = TestCompilationCacheKey.Grouped(testCaseId.testCaseGroupId, testCase.freeCompilerArgs, testRunnerType) - val testCompilation = cachedCompilations.computeIfAbsent(cacheKey) { + cachedCompilations.computeIfAbsent( + TestCompilationCacheKey.Grouped( + testCaseGroupId = testCaseId.testCaseGroupId, + freeCompilerArgs = testCase.freeCompilerArgs, + runnerType = testRunnerType + ) + ) { val testCases = testCaseGroup.getRegularOnly(testCase.freeCompilerArgs, testRunnerType) assertTrue(testCases.isNotEmpty()) compilationFactory.testCasesToExecutable(testCases, settings) } - testCompilation to cacheKey } } - val (artifact, loggedCompilerCall) = testCompilation.result.assertSuccess() // <-- Compilation happens here. - val executable = TestExecutable(artifact.executableFile, loggedCompilerCall) + val compilationResult = testCompilation.result.assertSuccess() // <-- Compilation happens here. + val executable = TestExecutable.fromCompilationResult(testCase, compilationResult) - return action(testCase, executable, cacheKey) + return action(testCase, executable) } private fun Collection.filterIrrelevant(testCase: TestCase) =