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