1 /*
2  * Copyright (C) 2017 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 android.media.cts.bitstreams;
18 
19 import com.android.tradefed.config.Configuration;
20 import com.android.tradefed.device.DeviceNotAvailableException;
21 import com.android.tradefed.device.ITestDevice;
22 import com.android.tradefed.invoker.TestInformation;
23 import com.android.tradefed.log.LogUtil.CLog;
24 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
25 import com.android.tradefed.result.ITestInvocationListener;
26 import com.android.tradefed.result.TestDescription;
27 import com.android.tradefed.testtype.AndroidJUnitTest;
28 import com.android.tradefed.util.FileUtil;
29 
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Map;
35 import java.util.Map.Entry;
36 
37 /**
38  * A {@link ReportProcessor} installs {@code CtsMediaBitstreamsDeviceSideTestApp.apk}
39  * onto a test device, invokes a report-generating test, then pulls and processes
40  * the generated report.
41  */
42 abstract class ReportProcessor {
43 
44     private final Map<String, String> mMetrics = new HashMap<>();
45     private String mFailureStackTrace = null;
46 
47     private static final String APP_CLS_NAME = "MediaBitstreamsDeviceSideTest";
48     private static final String APP_PKG_NAME = "android.media.cts.bitstreams.app";
49 
50     /**
51      * Setup {@code device} before test.
52      *
53      * @param device device under test
54      * @throws DeviceNotAvailableException
55      * @throws IOException
56      */
setUp(ITestDevice device)57     void setUp(ITestDevice device) throws DeviceNotAvailableException, IOException {}
58 
getArgs()59     Map<String, String> getArgs() {
60         return Collections.emptyMap();
61     }
62 
63     /**
64      * Process test report.
65      *
66      * @param device device under test
67      * @param reportPath path to test report on {@code device}
68      * @throws DeviceNotAvailableException
69      * @throws IOException
70      */
process(ITestDevice device, String reportPath)71     void process(ITestDevice device, String reportPath)
72             throws DeviceNotAvailableException, IOException {}
73 
74     /**
75      * Attempt to recover from a crash during test on {@code device}.
76      *
77      * @param device device under test
78      * @param reportPath path to test report on {@code device}
79      * @throws DeviceNotAvailableException
80      * @throws IOException
81      * @return true if successfully recovered from test crash, false otherwise
82      */
recover(ITestDevice device, String reportPath)83     boolean recover(ITestDevice device, String reportPath)
84             throws DeviceNotAvailableException, IOException {
85         return false;
86     }
87 
88     /**
89      * Cleanup {@code device} after test
90      * @param device device under test
91      * @param reportPath path to test report on {@code device}
92      */
cleanup(ITestDevice device, String reportPath)93     void cleanup(ITestDevice device, String reportPath) {
94         try {
95             device.executeShellCommand(String.format("rm %s", reportPath));
96         } catch (DeviceNotAvailableException e) {
97             CLog.e(e);
98         }
99     }
100 
101     /**
102      * @param device device under test
103      * @param reportPath path to test report on {@code device}
104      * @return array of lines in report, sans newline
105      * @throws DeviceNotAvailableException
106      */
getReportLines(ITestDevice device, String reportPath)107     static String[] getReportLines(ITestDevice device, String reportPath)
108             throws DeviceNotAvailableException {
109         File reportFile = device.pullFile(reportPath);
110         try {
111             return FileUtil.readStringFromFile(reportFile).split("\n");
112         } catch (IOException e) {
113             CLog.w(e);
114             return new String[0];
115         } finally {
116             reportFile.delete();
117         }
118     }
119 
120     /* Special listener for setting MediaPreparer instance variable values */
121     private class MediaBitstreamsListener implements ITestInvocationListener {
122 
123         @Override
testEnded(TestDescription test, Map<String, String> metrics)124         public void testEnded(TestDescription test, Map<String, String> metrics) {
125             mMetrics.putAll(metrics);
126         }
127 
128         @Override
testEnded(TestDescription test, HashMap<String, Metric> metrics)129         public void testEnded(TestDescription test, HashMap<String, Metric> metrics) {
130             for (Entry<String, Metric> e: metrics.entrySet()) {
131                 mMetrics.put(e.getKey(), e.getValue().getMeasurements().getSingleString());
132             }
133         }
134 
135         @Override
testFailed(TestDescription test, String trace)136         public void testFailed(TestDescription test, String trace) {
137             mFailureStackTrace = trace;
138         }
139 
140     }
141 
runDeviceTest( TestInformation testInfo, ITestDevice device, String method, String reportKey, int testTimeout, long shellTimeout)142     private boolean runDeviceTest(
143             TestInformation testInfo,
144             ITestDevice device, String method, String reportKey, int testTimeout,
145             long shellTimeout)
146             throws DeviceNotAvailableException {
147 
148         String fullTestName = String.format("%s.%s#%s", APP_PKG_NAME, APP_CLS_NAME, method);
149         AndroidJUnitTest instrTest = new AndroidJUnitTest();
150         instrTest.setDevice(device);
151         instrTest.setPackageName(APP_PKG_NAME);
152         instrTest.addIncludeFilter(fullTestName);
153         instrTest.setTestTimeout(testTimeout);
154         instrTest.setShellTimeout(shellTimeout);
155         // disable rerun mode to avoid collecting tests first then running.
156         instrTest.setRerunMode(false);
157         // disable isolated storage to access sdcard
158         instrTest.setIsolatedStorage(false);
159         for (Entry<String, String> e : getArgs().entrySet()) {
160             instrTest.addInstrumentationArg(e.getKey(), e.getValue());
161         }
162         // AndroidJUnitTest requires a IConfiguration to work properly, add a stub to this
163         // implementation to avoid an NPE.
164         instrTest.setConfiguration(new Configuration("stub", "stub"));
165         instrTest.run(testInfo, new MediaBitstreamsListener());
166 
167         return checkFile(reportKey);
168 
169     }
170 
checkFile(String reportKey)171     private boolean checkFile(String reportKey) {
172         if (mFailureStackTrace != null) {
173             CLog.w("Retrieving bitstreams formats failed with trace:\n%s", mFailureStackTrace);
174             mFailureStackTrace = null;
175             return false;
176         } else if (!mMetrics.containsKey(reportKey)) {
177             CLog.w("Failed to generate file key=%s on device", reportKey);
178             return false;
179         }
180         return true;
181     }
182 
processDeviceReport(TestInformation testInfo, ITestDevice device, String method, String reportKey)183     void processDeviceReport(TestInformation testInfo,
184             ITestDevice device, String method, String reportKey)
185             throws DeviceNotAvailableException, IOException {
186         try {
187             setUp(device);
188             while (!runDeviceTest(testInfo, device, method, reportKey, 0, 0)) {
189                 if (!recover(device, mMetrics.get(reportKey))) {
190                     return;
191                 }
192             }
193             process(device, mMetrics.get(reportKey));
194         } finally {
195             cleanup(device, mMetrics.get(reportKey));
196         }
197     }
198 
199 }
200