1 /* 2 * Copyright (C) 2011 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.FileInputStreamSource; 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.FileUtil; 32 import com.android.tradefed.util.StreamUtil; 33 import com.android.tradefed.util.proto.TfMetricProtoUtil; 34 35 import org.junit.Assert; 36 37 import java.io.File; 38 import java.io.FileInputStream; 39 import java.io.IOException; 40 import java.io.InputStream; 41 import java.util.Arrays; 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.ListIterator; 45 import java.util.Map; 46 import java.util.concurrent.TimeUnit; 47 import java.util.regex.Matcher; 48 import java.util.regex.Pattern; 49 50 /** 51 * Runs the Media stress testcases. 52 * FIXME: more details 53 * <p/> 54 * Note that this test will not run properly unless /sdcard is mounted and writable. 55 */ 56 public class MediaStressTest implements IDeviceTest, IRemoteTest { 57 58 ITestDevice mTestDevice = null; 59 private static final String METRICS_RUN_NAME = "VideoRecordingStress"; 60 61 //Max test timeout - 2 hrs 62 private static final int MAX_TEST_TIMEOUT = 2 * 60 * 60 * 1000; 63 64 // Constants for running the tests 65 private static final String TEST_CLASS_NAME = 66 "com.android.mediaframeworktest.stress.MediaRecorderStressTest"; 67 private static final String TEST_PACKAGE_NAME = "com.android.mediaframeworktest"; 68 private static final String TEST_RUNNER_NAME = ".MediaRecorderStressTestRunner"; 69 70 // Constants for parsing the output file 71 private static final Pattern EXPECTED_LOOP_COUNT_PATTERN = 72 Pattern.compile("Total number of loops:\\s*(\\d+)"); 73 private static final Pattern ACTUAL_LOOP_COUNT_PATTERN = 74 Pattern.compile("No of loop:.*,\\s*(\\d+)\\s*"); 75 private static final String OUTPUT_PATH = "mediaStressOutput.txt"; 76 77 @Override run(ITestInvocationListener listener)78 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 79 Assert.assertNotNull(mTestDevice); 80 81 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME, 82 TEST_RUNNER_NAME, mTestDevice.getIDevice()); 83 runner.setClassName(TEST_CLASS_NAME); 84 runner.setMaxTimeToOutputResponse(MAX_TEST_TIMEOUT, TimeUnit.MILLISECONDS); 85 86 cleanTmpFiles(); 87 mTestDevice.runInstrumentationTests(runner, listener); 88 logOutputFile(listener); 89 cleanTmpFiles(); 90 } 91 92 /** 93 * Clean up temp files from test runs 94 */ cleanTmpFiles()95 private void cleanTmpFiles() throws DeviceNotAvailableException { 96 String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 97 mTestDevice.executeShellCommand(String.format("rm %s/temp*.3gp", extStore)); 98 mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, OUTPUT_PATH)); 99 } 100 101 /** 102 * Pull the output file from the device, add it to the logs, and also parse out the relevant 103 * test metrics and report them. 104 */ logOutputFile(ITestInvocationListener listener)105 private void logOutputFile(ITestInvocationListener listener) 106 throws DeviceNotAvailableException { 107 File outputFile = null; 108 InputStreamSource outputSource = null; 109 try { 110 outputFile = mTestDevice.pullFileFromExternal(OUTPUT_PATH); 111 112 if (outputFile == null) { 113 return; 114 } 115 116 CLog.d("Sending %d byte file %s into the logosphere!", outputFile.length(), outputFile); 117 outputSource = new FileInputStreamSource(outputFile); 118 listener.testLog(OUTPUT_PATH, LogDataType.TEXT, outputSource); 119 parseOutputFile(outputFile, listener); 120 } finally { 121 FileUtil.deleteFile(outputFile); 122 StreamUtil.cancel(outputSource); 123 } 124 } 125 126 /** 127 * Parse the relevant metrics from the Instrumentation test output file 128 */ parseOutputFile(File outputFile, ITestInvocationListener listener)129 private void parseOutputFile(File outputFile, ITestInvocationListener listener) { 130 Map<String, String> runMetrics = new HashMap<>(); 131 Map<String, String> stanzaKeyMap = new HashMap<>(); 132 stanzaKeyMap.put("testStressRecordVideoAndPlayback1080P", "VideoRecordPlayback1080P"); 133 stanzaKeyMap.put("testStressRecordVideoAndPlayback720P", "VideoRecordPlayback720P"); 134 stanzaKeyMap.put("testStressRecordVideoAndPlayback480P", "VideoRecordPlayback480P"); 135 stanzaKeyMap.put("testStressTimeLapse", "TimeLapseRecord"); 136 137 // try to parse it 138 String contents; 139 try { 140 InputStream dataStream = new FileInputStream(outputFile); 141 contents = StreamUtil.getStringFromStream(dataStream); 142 } catch (IOException e) { 143 CLog.e("IOException while parsing the output file:"); 144 CLog.e(e); 145 return; 146 } 147 148 List<String> lines = Arrays.asList(contents.split("\n")); 149 ListIterator<String> lineIter = lines.listIterator(); 150 String line; 151 while (lineIter.hasNext()) { 152 line = lineIter.next(); 153 String key = null; 154 155 if (stanzaKeyMap.containsKey(line)) { 156 key = stanzaKeyMap.get(line); 157 } else { 158 CLog.d("Got unexpected line: %s", line); 159 continue; 160 } 161 162 Integer countExpected = getIntFromOutput(lineIter, EXPECTED_LOOP_COUNT_PATTERN); 163 Integer countActual = getIntFromOutput(lineIter, ACTUAL_LOOP_COUNT_PATTERN); 164 int value = coalesceLoopCounts(countActual, countExpected); 165 runMetrics.put(key, Integer.toString(value)); 166 } 167 168 reportMetrics(listener, runMetrics); 169 } 170 171 /** 172 * Report run metrics by creating an empty test run to stick them in 173 * <p /> 174 * Exposed for unit testing 175 */ reportMetrics(ITestInvocationListener listener, Map<String, String> metrics)176 void reportMetrics(ITestInvocationListener listener, Map<String, String> metrics) { 177 // Create an empty testRun to report the parsed runMetrics 178 CLog.d("About to report metrics: %s", metrics); 179 listener.testRunStarted(METRICS_RUN_NAME, 0); 180 listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics)); 181 } 182 183 /** 184 * Use the provided {@link Pattern} to parse a number out of the output file 185 */ getIntFromOutput(ListIterator<String> lineIter, Pattern numPattern)186 private Integer getIntFromOutput(ListIterator<String> lineIter, Pattern numPattern) { 187 Integer retval = null; 188 String line = null; 189 if (lineIter.hasNext()) { 190 line = lineIter.next(); 191 Matcher m = numPattern.matcher(line); 192 if (m.matches()) { 193 retval = Integer.parseInt(m.group(1)); 194 } else { 195 CLog.e("Couldn't match pattern %s against line '%s'", numPattern, line); 196 } 197 } else { 198 CLog.e("Encounted EOF while trying to match pattern %s", numPattern); 199 } 200 201 return retval; 202 } 203 204 /** 205 * Given an actual and an expected iteration count, determine a single metric to report. 206 */ coalesceLoopCounts(Integer actual, Integer expected)207 private int coalesceLoopCounts(Integer actual, Integer expected) { 208 if (expected == null || expected <= 0) { 209 return -1; 210 } else if (actual == null) { 211 return expected; 212 } else { 213 return actual; 214 } 215 } 216 217 @Override setDevice(ITestDevice device)218 public void setDevice(ITestDevice device) { 219 mTestDevice = device; 220 } 221 222 @Override getDevice()223 public ITestDevice getDevice() { 224 return mTestDevice; 225 } 226 } 227