1 /* <lambda>null2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.benchmark.macro 18 19 import android.util.Log 20 import androidx.benchmark.InstrumentationResults 21 import androidx.benchmark.Outputs 22 import androidx.benchmark.perfetto.UiState 23 import androidx.benchmark.perfetto.appendUiState 24 import java.io.File 25 import org.junit.rules.RuleChain 26 import org.junit.rules.TestRule 27 import org.junit.runner.Description 28 import org.junit.runners.model.Statement 29 30 /** 31 * Rule to enable linking files and traces to Studio UI for macrobench correctness tests. 32 * 33 * Filepaths are registered, and reported, but files are not created by this class, that should be 34 * handled by the test. Ensure you don't clean up the file - it needs to persist to be copied over 35 * by Studio. 36 */ 37 class FileLinkingRule : TestRule { 38 private lateinit var currentDescription: Description 39 private var summaryString = "" 40 41 private fun createReportedFilePath( 42 label: String, 43 @Suppress("SameParameterValue") extension: String, 44 ): String { 45 // remove parens / brackets, as it confuses linking 46 val methodLabel = 47 currentDescription 48 .toUniqueName() 49 .replace("(", "_") 50 .replace(")", "_") 51 .replace("[", "_") 52 .replace("]", "_") 53 54 val file = 55 File(Outputs.dirUsableByAppAndShell, "${label}_${Outputs.dateToFileName()}.$extension") 56 val absolutePath: String = file.absolutePath 57 val relativePath = Outputs.relativePathFor(absolutePath) 58 59 summaryString += "$methodLabel [$label](file://$relativePath)\n" 60 return absolutePath 61 } 62 63 /** 64 * Map of trace abs path -> process to highlight. 65 * 66 * After trace is complete (at end of test), we write a UI state packet to it, so trace UI can 67 * highlight/select the relevant process. 68 */ 69 private val traceToPackageMap = mutableMapOf<String, String>() 70 71 fun createReportedTracePath(packageName: String, label: String = "trace"): String { 72 val absolutePath = createReportedFilePath(label, "perfetto-trace") 73 traceToPackageMap[absolutePath] = packageName 74 return absolutePath 75 } 76 77 override fun apply(base: Statement, description: Description): Statement { 78 return RuleChain.outerRule(::applyInternal).apply(base, description) 79 } 80 81 private fun applyInternal(base: Statement, description: Description) = 82 object : Statement() { 83 override fun evaluate() { 84 currentDescription = description 85 try { 86 base.evaluate() 87 } finally { 88 flush() 89 } 90 } 91 } 92 93 private fun flush() { 94 traceToPackageMap.forEach { entry -> 95 File(entry.key).apply { 96 if (exists()) { 97 appendUiState(UiState(null, null, entry.value)) 98 } 99 } 100 } 101 102 if (Outputs.outputDirectory == Outputs.dirUsableByAppAndShell) { 103 InstrumentationResults.instrumentationReport { 104 reportSummaryToIde(message = summaryString.trim()) 105 } 106 } else { 107 Log.d(TAG, "FileLinkingRule doesn't support outputDirectory != dirUsableByAppAndShell") 108 } 109 } 110 111 private fun Description.toUniqueName() = testClass.simpleName + "_" + methodName 112 } 113