1 /* 2 * Copyright (C) 2010 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 com.android.cts.verifier; 18 19 import android.content.Context; 20 import android.os.Build; 21 import android.text.TextUtils; 22 23 import com.android.compatibility.common.util.DevicePropertyInfo; 24 import com.android.compatibility.common.util.ICaseResult; 25 import com.android.compatibility.common.util.IInvocationResult; 26 import com.android.compatibility.common.util.IModuleResult; 27 import com.android.compatibility.common.util.ITestResult; 28 import com.android.compatibility.common.util.InvocationResult; 29 import com.android.compatibility.common.util.ReportLog; 30 import com.android.compatibility.common.util.TestResultHistory; 31 import com.android.compatibility.common.util.TestScreenshotsMetadata; 32 import com.android.compatibility.common.util.TestStatus; 33 import com.android.cts.verifier.TestListActivity.DisplayMode; 34 import com.android.cts.verifier.TestListAdapter.TestListItem; 35 36 import java.text.DateFormat; 37 import java.text.SimpleDateFormat; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.HashSet; 41 import java.util.List; 42 import java.util.Locale; 43 import java.util.Map.Entry; 44 import java.util.Set; 45 46 /** 47 * Helper class for creating an {@code InvocationResult} for CTS result generation. 48 */ 49 class TestResultsReport { 50 51 /** Version of the test report. Increment whenever adding new tags and attributes. */ 52 private static final int REPORT_VERSION = 2; 53 54 /** Format of the report's creation time. Maintain the same format at CTS. */ 55 private static DateFormat DATE_FORMAT = 56 new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); 57 58 private static final String PREFIX_TAG = "build_"; 59 private static final String TEST_RESULTS_REPORT_TAG = "test-results-report"; 60 private static final String VERIFIER_INFO_TAG = "verifier-info"; 61 private static final String DEVICE_INFO_TAG = "device-info"; 62 private static final String BUILD_INFO_TAG = "build-info"; 63 private static final String TEST_RESULTS_TAG = "test-results"; 64 private static final String TEST_TAG = "test"; 65 private static final String TEST_DETAILS_TAG = "details"; 66 67 private static final String TEST_CASE_NAME = "manualTests"; 68 private static final String HOST_TEST_CASE_NAME = "hostTests"; 69 70 private final Context mContext; 71 72 private final TestListAdapter mAdapter; 73 TestResultsReport(Context context, TestListAdapter adapter)74 TestResultsReport(Context context, TestListAdapter adapter) { 75 this.mContext = context; 76 this.mAdapter = adapter; 77 } 78 generateResult()79 IInvocationResult generateResult() { 80 String abis = null; 81 String abis32 = null; 82 String abis64 = null; 83 String versionBaseOs = null; 84 String versionSecurityPatch = null; 85 String versionRelease = null; 86 IInvocationResult result = new InvocationResult(); 87 IModuleResult moduleResult = result.getOrCreateModule( 88 mContext.getResources().getString(R.string.module_id)); 89 90 // Collect build fields available in API level 21 91 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 92 abis = TextUtils.join(",", Build.SUPPORTED_ABIS); 93 abis32 = TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS); 94 abis64 = TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS); 95 } 96 97 // Collect build fields available in API level 23 98 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 99 versionBaseOs = Build.VERSION.BASE_OS; 100 versionSecurityPatch = Build.VERSION.SECURITY_PATCH; 101 } 102 103 versionRelease = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) 104 ? Build.VERSION.RELEASE_OR_CODENAME : Build.VERSION.RELEASE; 105 106 // at the time of writing, the build class has no REFERENCE_FINGERPRINT property 107 String referenceFingerprint = null; 108 109 DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(Build.CPU_ABI, 110 Build.CPU_ABI2, abis, abis32, abis64, Build.BOARD, Build.BRAND, Build.DEVICE, 111 Build.FINGERPRINT, null, Build.ID, Build.MANUFACTURER, Build.MODEL, Build.PRODUCT, 112 referenceFingerprint, Build.getSerial(), Build.TAGS, Build.TYPE, versionBaseOs, 113 versionRelease, Integer.toString(Build.VERSION.SDK_INT), 114 versionSecurityPatch, Build.VERSION.INCREMENTAL); 115 116 // add device properties to the result with a prefix tag for each key 117 for (Entry<String, String> entry : 118 devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) { 119 String entryValue = entry.getValue(); 120 if (entryValue != null) { 121 result.addInvocationInfo(entry.getKey(), entry.getValue()); 122 } 123 } 124 125 // Get test result, including test name, result, report log, details and histories. 126 getCaseResult(moduleResult); 127 getHostCaseResult(moduleResult); 128 129 return result; 130 } 131 getContents()132 String getContents() { 133 // TODO: remove getContents and everything that depends on it 134 return "Report viewing is deprecated. See contents on the SD Card."; 135 } 136 137 /** 138 * Get case results per test, including result, report log, details and histories. 139 * 140 * @param IModuleResult The module result bound with {@link IInvocationResult}. 141 */ getCaseResult(IModuleResult moduleResult)142 private void getCaseResult(IModuleResult moduleResult) { 143 ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME); 144 String hostTestTitle = mContext.getResources().getString(R.string.host_tests_title); 145 int notExecutedCount = 0; 146 for (DisplayMode mode: DisplayMode.values()) { 147 String displayMode = mode.toString(); 148 int count = mAdapter.getCount(displayMode); 149 for (int i = 0; i < count; i++) { 150 TestListItem item = mAdapter.getItem(displayMode, i); 151 String testName = item.testName; 152 if (item.isTest() && !item.title.equals(hostTestTitle)) { 153 createTestResult(caseResult, testName, testName); 154 if (mAdapter.getTestResult(testName) == TestResult.TEST_RESULT_NOT_EXECUTED) { 155 ++notExecutedCount; 156 } 157 } 158 } 159 } 160 moduleResult.setDone(true); 161 moduleResult.setNotExecuted(notExecutedCount); 162 } 163 164 /** 165 * Get case results per host test, including result, report log, details and histories. 166 * 167 * @param moduleResult The module result bound with {@link IInvocationResult}. 168 */ getHostCaseResult(IModuleResult moduleResult)169 private void getHostCaseResult(IModuleResult moduleResult) { 170 ICaseResult caseResult = moduleResult.getOrCreateResult(HOST_TEST_CASE_NAME); 171 for (String module : mContext.getResources().getStringArray(R.array.host_modules)) { 172 for (String testName : mAdapter.getTestResultNames()) { 173 if (!testName.startsWith(module)) { 174 continue; 175 } 176 // Split Module and Class#TestCase 177 String[] parts = testName.split(HostTestsActivity.TEST_ID_SEPARATOR, 2); 178 if (parts.length < 2 || !parts[1].contains(HostTestsActivity.TEST_ID_SEPARATOR)) { 179 continue; 180 } 181 createTestResult(caseResult, testName, parts[1]); 182 } 183 } 184 } 185 createTestResult(ICaseResult caseResult, String testName, String resultName)186 private void createTestResult(ICaseResult caseResult, String testName, String resultName) { 187 ITestResult currentTestResult = caseResult.getOrCreateResult(resultName); 188 TestStatus resultStatus = getTestResultStatus(mAdapter.getTestResult(testName)); 189 190 currentTestResult.setResultStatus(resultStatus); 191 // TODO: report test details with Extended Device Info (EDI) or CTS metrics 192 String details = mAdapter.getTestDetails(testName); 193 currentTestResult.setMessage(details); 194 195 ReportLog reportLog = mAdapter.getReportLog(testName); 196 if (reportLog != null) { 197 currentTestResult.setReportLog(reportLog); 198 } 199 200 TestResultHistoryCollection historyCollection = mAdapter.getHistoryCollection(testName); 201 if (historyCollection != null) { 202 List<TestResultHistory> leafTestHistories = getTestResultHistories(historyCollection); 203 currentTestResult.setTestResultHistories(leafTestHistories); 204 } 205 206 TestScreenshotsMetadata screenshotsMetadata = mAdapter.getScreenshotsMetadata(testName); 207 if (screenshotsMetadata != null) { 208 currentTestResult.setTestScreenshotsMetadata(screenshotsMetadata); 209 } 210 } 211 getTestResultStatus(int testResult)212 private TestStatus getTestResultStatus(int testResult) { 213 switch (testResult) { 214 case TestResult.TEST_RESULT_PASSED: 215 return TestStatus.PASS; 216 217 case TestResult.TEST_RESULT_FAILED: 218 return TestStatus.FAIL; 219 220 case TestResult.TEST_RESULT_NOT_EXECUTED: 221 return null; 222 223 default: 224 throw new IllegalArgumentException("Unknown test result: " + testResult); 225 } 226 } 227 228 /** 229 * Get test histories per test by filtering out non-leaf histories. 230 * 231 * @param TestResultHistoryCollection The raw test history collection. 232 * @return A list containing test result histories per test. 233 */ 234 @SuppressWarnings("ReturnValueIgnored") getTestResultHistories( TestResultHistoryCollection historyCollection)235 private List<TestResultHistory> getTestResultHistories( 236 TestResultHistoryCollection historyCollection) { 237 // Get non-terminal prefixes. 238 Set<String> prefixes = new HashSet<>(); 239 for (TestResultHistory history : historyCollection.asSet()) { 240 Arrays.stream(history.getTestName().split(":")).reduce( 241 (total, current) -> { 242 prefixes.add(total); 243 return total + ":" + current; 244 }); 245 } 246 247 // Filter out non-leaf test histories. 248 List<TestResultHistory> leafTestHistories = 249 new ArrayList<TestResultHistory>(); 250 for (TestResultHistory history : historyCollection.asSet()) { 251 if (!prefixes.contains(history.getTestName())) { 252 leafTestHistories.add(history); 253 } 254 } 255 return leafTestHistories; 256 } 257 } 258