1 /* 2 * Copyright (C) 2012 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.media.tests; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; 21 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.log.LogUtil.CLog; 25 import com.android.tradefed.result.BugreportCollector; 26 import com.android.tradefed.result.ITestInvocationListener; 27 import com.android.tradefed.result.InputStreamSource; 28 import com.android.tradefed.result.LogDataType; 29 import com.android.tradefed.testtype.IDeviceTest; 30 import com.android.tradefed.testtype.IRemoteTest; 31 import com.android.tradefed.util.proto.TfMetricProtoUtil; 32 33 import org.junit.Assert; 34 35 import java.io.BufferedReader; 36 import java.io.File; 37 import java.io.FileReader; 38 import java.io.IOException; 39 import java.util.HashMap; 40 import java.util.Map; 41 import java.util.regex.Matcher; 42 import java.util.regex.Pattern; 43 44 public class CameraShotToShotLatencyTest implements IDeviceTest, IRemoteTest { 45 46 private static final Pattern MEAN_PATTERN = 47 Pattern.compile("(Shot to shot latency - mean:)(\\s*)(\\d+\\.\\d*)"); 48 private static final Pattern STANDARD_DEVIATION_PATTERN = 49 Pattern.compile("(Shot to shot latency - standard deviation:)(\\s*)(\\d+\\.\\d*)"); 50 51 private static final String TEST_CLASS_NAME = "com.android.camera.stress.ShotToShotLatency"; 52 private static final String TEST_PACKAGE_NAME = "com.google.android.camera.tests"; 53 private static final String TEST_RUNNER_NAME = "android.test.InstrumentationTestRunner"; 54 55 private static final String LATENCY_KEY_MEAN = "Shot2ShotLatencyMean"; 56 private static final String LATENCY_KEY_SD = "Shot2ShotLatencySD"; 57 private static final String TEST_RU = "CameraLatency"; 58 59 private final String mOutputPath = "mediaStressOut.txt"; 60 ITestDevice mTestDevice = null; 61 62 /** 63 * {@inheritDoc} 64 */ 65 @Override run(ITestInvocationListener listener)66 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 67 Assert.assertNotNull(mTestDevice); 68 69 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME, 70 TEST_RUNNER_NAME, mTestDevice.getIDevice()); 71 runner.setClassName(TEST_CLASS_NAME); 72 73 BugreportCollector bugListener = new BugreportCollector(listener, mTestDevice); 74 bugListener.addPredicate(BugreportCollector.AFTER_FAILED_TESTCASES); 75 bugListener.setDescriptiveName(this.getClass().getName()); 76 Assert.assertTrue(mTestDevice.runInstrumentationTests(runner, bugListener)); 77 78 Map<String, String> metrics = parseOutputFile(); 79 reportMetrics(bugListener, TEST_RU, metrics); 80 cleanupDevice(); 81 } 82 83 /** 84 * {@inheritDoc} 85 */ 86 @Override setDevice(ITestDevice device)87 public void setDevice(ITestDevice device) { 88 mTestDevice = device; 89 } 90 91 /** 92 * {@inheritDoc} 93 */ 94 @Override getDevice()95 public ITestDevice getDevice() { 96 return mTestDevice; 97 } 98 99 /** 100 * Wipes the device's external memory of test collateral from prior runs. 101 * Note that all photos on the test device will be removed. 102 * @throws DeviceNotAvailableException If the device is unavailable or 103 * something happened while deleting files 104 */ cleanupDevice()105 private void cleanupDevice() throws DeviceNotAvailableException { 106 String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 107 mTestDevice.executeShellCommand(String.format("rm -r %s/DCIM", extStore)); 108 mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, mOutputPath)); 109 } 110 111 /** 112 * Parses the output file generated by the underlying instrumentation test 113 * and returns the metrics to the main driver for later reporting. 114 * @return The {@link Map} that contains metrics for the test. 115 * @throws DeviceNotAvailableException If the device is unavailable or 116 * something happened while deleting files 117 */ parseOutputFile()118 private Map<String, String> parseOutputFile() throws DeviceNotAvailableException { 119 BufferedReader reader = null; 120 File outputFile = null; 121 String lineMean = null, lineSd = null; 122 Matcher m = null; 123 Map<String, String> metrics = new HashMap<String, String>(); 124 125 // Read in data 126 // Output file is only 2 lines and should look something like: 127 // "Shot to shot latency - mean: 1234.5678901" 128 // "Shot to shot latency - standard deviation: 123.45678901" 129 try { 130 outputFile = mTestDevice.pullFileFromExternal(mOutputPath); 131 reader = new BufferedReader(new FileReader(outputFile)); 132 133 lineMean = reader.readLine(); 134 lineSd = reader.readLine(); 135 136 if ((lineMean == null) || (lineSd == null)) { 137 CLog.e(String.format("Unable to find output data; hit EOF: \nmean:%s\nsd:%s", 138 lineMean, lineSd)); 139 } else { 140 m = MEAN_PATTERN.matcher(lineMean); 141 if (m.matches()) { 142 metrics.put(LATENCY_KEY_MEAN, m.group(3)); 143 } else { 144 CLog.e(String.format("Unable to find mean: %s", lineMean)); 145 } 146 147 m = STANDARD_DEVIATION_PATTERN.matcher(lineSd); 148 if (m.matches()) { 149 metrics.put(LATENCY_KEY_SD, m.group(3)); 150 } else { 151 CLog.e(String.format("Unable to find standard deviation: %s", lineSd)); 152 } 153 } 154 } catch (IOException e) { 155 CLog.e(String.format("IOException reading from file: %s", e.toString())); 156 } finally { 157 if (reader != null) { 158 try { 159 reader.close(); 160 } catch (IOException e) { 161 CLog.e(String.format("IOException closing file: %s", e.toString())); 162 } 163 } 164 } 165 166 return metrics; 167 } 168 169 /** 170 * Report run metrics by creating an empty test run to stick them in. 171 * @param listener The {@link ITestInvocationListener} of test results 172 * @param runName The test name 173 * @param metrics The {@link Map} that contains metrics for the given test 174 */ reportMetrics(ITestInvocationListener listener, String runName, Map<String, String> metrics)175 private void reportMetrics(ITestInvocationListener listener, String runName, 176 Map<String, String> metrics) { 177 InputStreamSource bugreport = mTestDevice.getBugreport(); 178 listener.testLog("bugreport", LogDataType.BUGREPORT, bugreport); 179 bugreport.close(); 180 181 CLog.d(String.format("About to report metrics: %s", metrics)); 182 listener.testRunStarted(runName, 0); 183 listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics)); 184 } 185 } 186