diff --git a/test_runner/src/main/kotlin/ftl/reports/api/PerformanceMetrics.kt b/test_runner/src/main/kotlin/ftl/reports/api/PerformanceMetrics.kt index 1e8f05ca3e..4f74e54fa5 100644 --- a/test_runner/src/main/kotlin/ftl/reports/api/PerformanceMetrics.kt +++ b/test_runner/src/main/kotlin/ftl/reports/api/PerformanceMetrics.kt @@ -3,25 +3,39 @@ package ftl.reports.api import com.google.api.services.testing.model.TestExecution import com.google.api.services.toolresults.model.PerfMetricsSummary import ftl.android.AndroidCatalog +import ftl.args.IArgs import ftl.gc.GcStorage import ftl.gc.GcToolResults import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.runBlocking +import java.nio.file.Files +import java.nio.file.Paths internal fun List>.getAndUploadPerformanceMetrics( - resultBucket: String + args: IArgs ) = runBlocking { filterAndroidPhysicalDevicesRuns() .map { (testExecution, gcsStoragePath) -> async(Dispatchers.IO) { - testExecution.getPerformanceMetric().upload(resultBucket = resultBucket, resultDir = gcsStoragePath) + val performanceMetrics = testExecution.getPerformanceMetric() + performanceMetrics.save(gcsStoragePath, args) + performanceMetrics.upload(resultBucket = args.resultsBucket, resultDir = gcsStoragePath) } } .awaitAll() } +private fun PerfMetricsSummary.save(resultsDir: String, args: IArgs) { + val configFilePath = if (args.useLocalResultDir()) + Paths.get(args.localResultDir, "performanceMetrics.json") else + Paths.get(args.localResultDir, resultsDir, "performanceMetrics.json") + + configFilePath.parent.toFile().mkdirs() + Files.write(configFilePath, toPrettyString().toByteArray()) +} + private fun List>.filterAndroidPhysicalDevicesRuns() = filterNot { (testExecution, _) -> AndroidCatalog.isVirtualDevice(testExecution.environment.androidDevice, testExecution.projectId) } diff --git a/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt b/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt index 0d9180e7f9..e3027a156a 100644 --- a/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt +++ b/test_runner/src/main/kotlin/ftl/reports/util/ReportManager.kt @@ -143,9 +143,7 @@ object ReportManager { ) { testExecutions .takeIf { args is AndroidArgs } - ?.run { - withGcsStoragePath(matrices, args.resultsDir).getAndUploadPerformanceMetrics(args.resultsBucket) - } + ?.run { withGcsStoragePath(matrices, args.resultsDir).getAndUploadPerformanceMetrics(args) } } private fun List.withGcsStoragePath( diff --git a/test_runner/src/main/kotlin/ftl/run/NewTestRun.kt b/test_runner/src/main/kotlin/ftl/run/NewTestRun.kt index 01345d1552..bbdb85b9e2 100644 --- a/test_runner/src/main/kotlin/ftl/run/NewTestRun.kt +++ b/test_runner/src/main/kotlin/ftl/run/NewTestRun.kt @@ -24,9 +24,8 @@ suspend fun newTestRun(args: IArgs) = withTimeoutOrNull(args.parsedTimeout) { if (!args.async) { cancelTestsOnTimeout(args.project, matrixMap.map) { pollMatrices(matrixMap.map.keys, args).updateMatrixMap(matrixMap) } - cancelTestsOnTimeout(args.project, matrixMap.map) { fetchArtifacts(matrixMap, args) } - ReportManager.generate(matrixMap, args, testShardChunks, ignoredTests) + cancelTestsOnTimeout(args.project, matrixMap.map) { fetchArtifacts(matrixMap, args) } println() matrixMap.printMatricesWebLinks(args.project) diff --git a/test_runner/src/main/kotlin/ftl/run/common/FetchArtifacts.kt b/test_runner/src/main/kotlin/ftl/run/common/FetchArtifacts.kt index db30857dc6..25b57b8e67 100644 --- a/test_runner/src/main/kotlin/ftl/run/common/FetchArtifacts.kt +++ b/test_runner/src/main/kotlin/ftl/run/common/FetchArtifacts.kt @@ -68,9 +68,9 @@ internal fun getDownloadPath(args: IArgs, blobPath: String): Path { val objName = if (args.useLocalResultDir()) "" else parsed.getName(0).toString() // for iOS it is shardName, remove this comment after FTL introduce server side sharding for iOS val matrixName = parsed.getName(1).toString() - val deviceName = parsed.getName(2).toString() - val filePathName = if (args.keepFilePath) parsed.parent.drop(3).joinToString("/") else "" val fileName = parsed.fileName.toString() + val deviceName = parsed.getName(2).toString().takeUnless { it == fileName }.orEmpty() + val filePathName = if (args.keepFilePath) parsed.parent.drop(3).joinToString("/") else "" return Paths.get("$localDir/$objName/$matrixName/$deviceName/$filePathName/$fileName") } diff --git a/test_runner/src/test/kotlin/ftl/reports/api/PerformanceMetricsTest.kt b/test_runner/src/test/kotlin/ftl/reports/api/PerformanceMetricsTest.kt index 63451dd911..08f233b87a 100644 --- a/test_runner/src/test/kotlin/ftl/reports/api/PerformanceMetricsTest.kt +++ b/test_runner/src/test/kotlin/ftl/reports/api/PerformanceMetricsTest.kt @@ -5,6 +5,7 @@ import com.google.api.services.testing.model.TestExecution import com.google.api.services.testing.model.ToolResultsStep import com.google.common.truth.Truth.assertThat import ftl.android.AndroidCatalog +import ftl.args.IArgs import ftl.gc.GcStorage import ftl.gc.GcToolResults import ftl.test.util.FlankTestRunner @@ -27,8 +28,11 @@ class PerformanceMetricsTest { fun `should not get and upload performance metrics for virtual devices`() { mockkObject(AndroidCatalog) { every { AndroidCatalog.isVirtualDevice(any(), any()) } returns true + val args = mockk { + every { resultsBucket } returns "b8ce" + } - assertThat(testExecutions.map { it to "path" }.getAndUploadPerformanceMetrics("b8ce")).isEmpty() + assertThat(testExecutions.map { it to "path" }.getAndUploadPerformanceMetrics(args)).isEmpty() } } @@ -44,7 +48,12 @@ class PerformanceMetricsTest { } mockkObject(GcStorage) { - testExecutions.map { it to expectedPath }.getAndUploadPerformanceMetrics(expectedBucket) + val args = mockk { + every { resultsBucket } returns expectedBucket + every { useLocalResultDir() } returns false + every { localResultDir } returns "local" + } + testExecutions.map { it to expectedPath }.getAndUploadPerformanceMetrics(args) performanceMetrics.forEach { verify { GcStorage.uploadPerformanceMetrics(it, expectedBucket, expectedPath) } }