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 import android.util.Xml; 23 24 import com.android.compatibility.common.util.DevicePropertyInfo; 25 import com.android.compatibility.common.util.ICaseResult; 26 import com.android.compatibility.common.util.IInvocationResult; 27 import com.android.compatibility.common.util.IModuleResult; 28 import com.android.compatibility.common.util.InvocationResult; 29 import com.android.compatibility.common.util.ITestResult; 30 import com.android.compatibility.common.util.MetricsXmlSerializer; 31 import com.android.compatibility.common.util.ReportLog; 32 import com.android.compatibility.common.util.TestResultHistory; 33 import com.android.compatibility.common.util.TestStatus; 34 import com.android.cts.verifier.TestListAdapter.TestListItem; 35 36 import org.xmlpull.v1.XmlSerializer; 37 38 import java.io.ByteArrayOutputStream; 39 import java.io.IOException; 40 import java.text.DateFormat; 41 import java.text.SimpleDateFormat; 42 import java.util.Arrays; 43 import java.util.ArrayList; 44 import java.util.Date; 45 import java.util.HashMap; 46 import java.util.HashSet; 47 import java.util.List; 48 import java.util.Locale; 49 import java.util.Map; 50 import java.util.Map.Entry; 51 import java.util.Set; 52 53 /** 54 * Helper class for creating an {@code InvocationResult} for CTS result generation. 55 */ 56 class TestResultsReport { 57 58 /** Version of the test report. Increment whenever adding new tags and attributes. */ 59 private static final int REPORT_VERSION = 2; 60 61 /** Format of the report's creation time. Maintain the same format at CTS. */ 62 private static DateFormat DATE_FORMAT = 63 new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); 64 65 private static final String PREFIX_TAG = "build_"; 66 private static final String TEST_RESULTS_REPORT_TAG = "test-results-report"; 67 private static final String VERIFIER_INFO_TAG = "verifier-info"; 68 private static final String DEVICE_INFO_TAG = "device-info"; 69 private static final String BUILD_INFO_TAG = "build-info"; 70 private static final String TEST_RESULTS_TAG = "test-results"; 71 private static final String TEST_TAG = "test"; 72 private static final String TEST_DETAILS_TAG = "details"; 73 74 private static final String MODULE_ID = "noabi CtsVerifier"; 75 private static final String TEST_CASE_NAME = "manualTests"; 76 77 private final Context mContext; 78 79 private final TestListAdapter mAdapter; 80 TestResultsReport(Context context, TestListAdapter adapter)81 TestResultsReport(Context context, TestListAdapter adapter) { 82 this.mContext = context; 83 this.mAdapter = adapter; 84 } 85 generateResult()86 IInvocationResult generateResult() { 87 String abis = null; 88 String abis32 = null; 89 String abis64 = null; 90 String versionBaseOs = null; 91 String versionSecurityPatch = null; 92 IInvocationResult result = new InvocationResult(); 93 IModuleResult moduleResult = result.getOrCreateModule(MODULE_ID); 94 95 // Collect build fields available in API level 21 96 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 97 abis = TextUtils.join(",", Build.SUPPORTED_ABIS); 98 abis32 = TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS); 99 abis64 = TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS); 100 } 101 102 // Collect build fields available in API level 23 103 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 104 versionBaseOs = Build.VERSION.BASE_OS; 105 versionSecurityPatch = Build.VERSION.SECURITY_PATCH; 106 } 107 108 // at the time of writing, the build class has no REFERENCE_FINGERPRINT property 109 String referenceFingerprint = null; 110 111 DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(Build.CPU_ABI, 112 Build.CPU_ABI2, abis, abis32, abis64, Build.BOARD, Build.BRAND, Build.DEVICE, 113 Build.FINGERPRINT, null, Build.ID, Build.MANUFACTURER, Build.MODEL, Build.PRODUCT, 114 referenceFingerprint, Build.getSerial(), Build.TAGS, Build.TYPE, versionBaseOs, 115 Build.VERSION.RELEASE, Integer.toString(Build.VERSION.SDK_INT), 116 versionSecurityPatch, Build.VERSION.INCREMENTAL); 117 118 // add device properties to the result with a prefix tag for each key 119 for (Entry<String, String> entry : 120 devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) { 121 String entryValue = entry.getValue(); 122 if (entryValue != null) { 123 result.addInvocationInfo(entry.getKey(), entry.getValue()); 124 } 125 } 126 127 ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME); 128 int count = mAdapter.getCount(); 129 int notExecutedCount = 0; 130 for (int i = 0; i < count; i++) { 131 TestListItem item = mAdapter.getItem(i); 132 if (item.isTest()) { 133 ITestResult currentTestResult = caseResult.getOrCreateResult(item.testName); 134 TestStatus resultStatus = getTestResultStatus(mAdapter.getTestResult(i)); 135 if (resultStatus == null) { 136 ++notExecutedCount; 137 } 138 currentTestResult.setResultStatus(resultStatus); 139 // TODO: report test details with Extended Device Info (EDI) or CTS metrics 140 String details = mAdapter.getTestDetails(i); 141 currentTestResult.setMessage(details); 142 143 ReportLog reportLog = mAdapter.getReportLog(i); 144 if (reportLog != null) { 145 currentTestResult.setReportLog(reportLog); 146 } 147 148 TestResultHistoryCollection historyCollection = mAdapter.getHistoryCollection(i); 149 if (historyCollection != null) { 150 // Get non-terminal prefixes. 151 Set<String> prefixes = new HashSet<>(); 152 for (TestResultHistory history: historyCollection.asSet()) { 153 Arrays.stream(history.getTestName().split(":")).reduce( 154 (total, current) -> { prefixes.add(total); 155 return total + ":" + current; 156 }); 157 } 158 159 // Filter out non-leaf test histories. 160 List<TestResultHistory> leafTestHistories = new ArrayList<TestResultHistory>(); 161 for (TestResultHistory history: historyCollection.asSet()) { 162 if (!prefixes.contains(history.getTestName())) { 163 leafTestHistories.add(history); 164 } 165 } 166 currentTestResult.setTestResultHistories(leafTestHistories); 167 } 168 } 169 } 170 moduleResult.setDone(true); 171 moduleResult.setNotExecuted(notExecutedCount); 172 173 return result; 174 } 175 getContents()176 String getContents() { 177 // TODO: remove getContents and everything that depends on it 178 return "Report viewing is deprecated. See contents on the SD Card."; 179 } 180 getTestResultStatus(int testResult)181 private TestStatus getTestResultStatus(int testResult) { 182 switch (testResult) { 183 case TestResult.TEST_RESULT_PASSED: 184 return TestStatus.PASS; 185 186 case TestResult.TEST_RESULT_FAILED: 187 return TestStatus.FAIL; 188 189 case TestResult.TEST_RESULT_NOT_EXECUTED: 190 return null; 191 192 default: 193 throw new IllegalArgumentException("Unknown test result: " + testResult); 194 } 195 } 196 } 197