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 
69     private final Context mContext;
70 
71     private final TestListAdapter mAdapter;
72 
TestResultsReport(Context context, TestListAdapter adapter)73     TestResultsReport(Context context, TestListAdapter adapter) {
74         this.mContext = context;
75         this.mAdapter = adapter;
76     }
77 
generateResult()78     IInvocationResult generateResult() {
79         String abis = null;
80         String abis32 = null;
81         String abis64 = null;
82         String versionBaseOs = null;
83         String versionSecurityPatch = null;
84         String versionRelease = null;
85         IInvocationResult result = new InvocationResult();
86         IModuleResult moduleResult = result.getOrCreateModule(
87                 mContext.getResources().getString(R.string.module_id));
88 
89         // Collect build fields available in API level 21
90         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
91             abis = TextUtils.join(",", Build.SUPPORTED_ABIS);
92             abis32 = TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS);
93             abis64 = TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS);
94         }
95 
96         // Collect build fields available in API level 23
97         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
98             versionBaseOs = Build.VERSION.BASE_OS;
99             versionSecurityPatch = Build.VERSION.SECURITY_PATCH;
100         }
101 
102         versionRelease = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
103                 ? Build.VERSION.RELEASE_OR_CODENAME : Build.VERSION.RELEASE;
104 
105         // at the time of writing, the build class has no REFERENCE_FINGERPRINT property
106         String referenceFingerprint = null;
107 
108         DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(Build.CPU_ABI,
109                 Build.CPU_ABI2, abis, abis32, abis64, Build.BOARD, Build.BRAND, Build.DEVICE,
110                 Build.FINGERPRINT, null, Build.ID, Build.MANUFACTURER, Build.MODEL, Build.PRODUCT,
111                 referenceFingerprint, Build.getSerial(), Build.TAGS, Build.TYPE, versionBaseOs,
112                 versionRelease, Integer.toString(Build.VERSION.SDK_INT),
113                 versionSecurityPatch, Build.VERSION.INCREMENTAL);
114 
115         // add device properties to the result with a prefix tag for each key
116         for (Entry<String, String> entry :
117                 devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) {
118             String entryValue = entry.getValue();
119             if (entryValue != null) {
120                 result.addInvocationInfo(entry.getKey(), entry.getValue());
121             }
122         }
123 
124         // Get test result, including test name, result, report log, details and histories.
125         getCaseResult(moduleResult);
126 
127         return result;
128     }
129 
getContents()130     String getContents() {
131         // TODO: remove getContents and everything that depends on it
132         return "Report viewing is deprecated. See contents on the SD Card.";
133     }
134 
135     /**
136      * Get case results per test, including result, report log, details and histories.
137      *
138      * @param IModuleResult The module result bound with {@link IInvocationResult}.
139      */
getCaseResult(IModuleResult moduleResult)140     private void getCaseResult(IModuleResult moduleResult) {
141         ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME);
142         int notExecutedCount = 0;
143         for (DisplayMode mode: DisplayMode.values()) {
144             String displayMode = mode.toString();
145             int count = mAdapter.getCount(displayMode);
146             for (int i = 0; i < count; i++) {
147                 TestListItem item = mAdapter.getItem(displayMode, i);
148                 if (item.isTest()) {
149                     ITestResult currentTestResult = caseResult.getOrCreateResult(item.testName);
150                     TestStatus resultStatus =
151                         getTestResultStatus(mAdapter.getTestResult(displayMode, i));
152                     if (resultStatus == null) {
153                         ++notExecutedCount;
154                     }
155                     currentTestResult.setResultStatus(resultStatus);
156                     // TODO: report test details with Extended Device Info (EDI) or CTS metrics
157                     String details = mAdapter.getTestDetails(displayMode, i);
158                     currentTestResult.setMessage(details);
159 
160                     ReportLog reportLog = mAdapter.getReportLog(displayMode, i);
161                     if (reportLog != null) {
162                         currentTestResult.setReportLog(reportLog);
163                     }
164 
165                     TestResultHistoryCollection historyCollection = mAdapter
166                         .getHistoryCollection(displayMode, i);
167                     if (historyCollection != null) {
168                         List<TestResultHistory> leafTestHistories =
169                             getTestResultHistories(historyCollection);
170                         currentTestResult.setTestResultHistories(leafTestHistories);
171                     }
172 
173                     TestScreenshotsMetadata screenshotsMetadata = mAdapter
174                             .getScreenshotsMetadata(displayMode, i);
175                     if (screenshotsMetadata != null) {
176                         currentTestResult.setTestScreenshotsMetadata(screenshotsMetadata);
177                     }
178                 }
179             }
180         }
181         moduleResult.setDone(true);
182         moduleResult.setNotExecuted(notExecutedCount);
183     }
184 
getTestResultStatus(int testResult)185     private TestStatus getTestResultStatus(int testResult) {
186         switch (testResult) {
187             case TestResult.TEST_RESULT_PASSED:
188                 return TestStatus.PASS;
189 
190             case TestResult.TEST_RESULT_FAILED:
191                 return TestStatus.FAIL;
192 
193             case TestResult.TEST_RESULT_NOT_EXECUTED:
194                 return null;
195 
196             default:
197                 throw new IllegalArgumentException("Unknown test result: " + testResult);
198         }
199     }
200 
201     /**
202      * Get test histories per test by filtering out non-leaf histories.
203      *
204      * @param TestResultHistoryCollection The raw test history collection.
205      * @return A list containing test result histories per test.
206      */
207     @SuppressWarnings("ReturnValueIgnored")
getTestResultHistories( TestResultHistoryCollection historyCollection)208     private List<TestResultHistory> getTestResultHistories(
209         TestResultHistoryCollection historyCollection) {
210         // Get non-terminal prefixes.
211         Set<String> prefixes = new HashSet<>();
212         for (TestResultHistory history : historyCollection.asSet()) {
213             Arrays.stream(history.getTestName().split(":")).reduce(
214                 (total, current) -> {
215                     prefixes.add(total);
216                     return total + ":" + current;
217                 });
218         }
219 
220         // Filter out non-leaf test histories.
221         List<TestResultHistory> leafTestHistories =
222             new ArrayList<TestResultHistory>();
223         for (TestResultHistory history : historyCollection.asSet()) {
224             if (!prefixes.contains(history.getTestName())) {
225                 leafTestHistories.add(history);
226             }
227         }
228         return leafTestHistories;
229     }
230 }
231