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