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.Log; 21 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; 22 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; 23 import com.android.tradefed.config.Option; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.result.BugreportCollector; 27 import com.android.tradefed.result.BugreportCollector.Freq; 28 import com.android.tradefed.result.BugreportCollector.Noun; 29 import com.android.tradefed.result.BugreportCollector.Relation; 30 import com.android.tradefed.result.FileInputStreamSource; 31 import com.android.tradefed.result.ITestInvocationListener; 32 import com.android.tradefed.result.InputStreamSource; 33 import com.android.tradefed.result.LogDataType; 34 import com.android.tradefed.testtype.IDeviceTest; 35 import com.android.tradefed.testtype.IRemoteTest; 36 import com.android.tradefed.util.FileUtil; 37 import com.android.tradefed.util.StreamUtil; 38 39 import org.junit.Assert; 40 41 import java.io.File; 42 import java.io.FileInputStream; 43 import java.io.IOException; 44 import java.io.InputStream; 45 import java.util.Arrays; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.ListIterator; 49 import java.util.Map; 50 import java.util.concurrent.TimeUnit; 51 import java.util.regex.Matcher; 52 import java.util.regex.Pattern; 53 54 /** 55 * Runs the Video Editing Framework Memory Tests. This test exercise the basic 56 * functionality of video editing test and capture the memory usage. The memory 57 * usage test out is saved in /sdcard/VideoEditorStressMemOutput.txt and 58 * VideoEditorMediaServerMemoryLog.txt. 59 * <p/> 60 * Note that this test will not run properly unless /sdcard is mounted and 61 * writable. 62 */ 63 public class VideoEditingMemoryTest implements IDeviceTest, IRemoteTest { 64 private static final String LOG_TAG = "VideoEditorMemoryTest"; 65 66 ITestDevice mTestDevice = null; 67 68 // Constants for running the tests 69 private static final String TEST_CLASS_NAME = 70 "com.android.mediaframeworktest.stress.VideoEditorStressTest"; 71 private static final String TEST_PACKAGE_NAME = "com.android.mediaframeworktest"; 72 private static final String TEST_RUNNER_NAME = ".MediaPlayerStressTestRunner"; 73 74 //Max test timeout - 3 hrs 75 private static final int MAX_TEST_TIMEOUT = 3 * 60 * 60 * 1000; 76 77 /* 78 * Pattern to find the test case name and test result. 79 * Example of a matching line: 80 * testStressAddRemoveEffects total diff = 0 81 * The first string 'testStressAddRemoveEffects' represent the dashboard key and 82 * the last string represent the test result. 83 */ 84 public static final Pattern TOTAL_MEM_DIFF_PATTERN = 85 Pattern.compile("(.+?)\\s.*diff.*\\s(-?\\d+)"); 86 87 public Map<String, String> mRunMetrics = new HashMap<>(); 88 public Map<String, String> mKeyMap = new HashMap<>(); 89 90 @Option(name = "getHeapDump", description = "Collect the heap") 91 private boolean mGetHeapDump = false; 92 93 public VideoEditingMemoryTest() { 94 mKeyMap.put("VideoEditorStressMemOutput.txt", "VideoEditorMemory"); 95 mKeyMap.put("VideoEditorMediaServerMemoryLog.txt", 96 "VideoEditorMemoryMediaServer"); 97 } 98 99 100 @Override 101 public void run(ITestInvocationListener listener) 102 throws DeviceNotAvailableException { 103 Assert.assertNotNull(mTestDevice); 104 105 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner( 106 TEST_PACKAGE_NAME, TEST_RUNNER_NAME, mTestDevice.getIDevice()); 107 runner.setClassName(TEST_CLASS_NAME); 108 runner.setMaxTimeToOutputResponse(MAX_TEST_TIMEOUT, TimeUnit.MILLISECONDS); 109 if (mGetHeapDump) { 110 runner.addInstrumentationArg("get_heap_dump", "getNativeHeap"); 111 } 112 113 BugreportCollector bugListener = new BugreportCollector(listener, 114 mTestDevice); 115 bugListener.addPredicate(new BugreportCollector.Predicate( 116 Relation.AFTER, Freq.EACH, Noun.TESTRUN)); 117 118 mTestDevice.runInstrumentationTests(runner, bugListener); 119 120 logOutputFiles(listener); 121 cleanResultFile(); 122 } 123 124 /** 125 * Clean up the test result file from test run 126 */ 127 private void cleanResultFile() throws DeviceNotAvailableException { 128 String extStore = 129 mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 130 for(String outFile : mKeyMap.keySet()) { 131 mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, 132 outFile)); 133 } 134 if (mGetHeapDump) { 135 mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, 136 "*.dump")); 137 } 138 } 139 140 private void uploadHeapDumpFiles(ITestInvocationListener listener) 141 throws DeviceNotAvailableException { 142 // Pull and upload the heap dump output files. 143 InputStreamSource outputSource = null; 144 File outputFile = null; 145 146 String extStore = 147 mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 148 149 String out = mTestDevice.executeShellCommand(String.format("ls %s/%s", 150 extStore, "*.dump")); 151 String heapOutputFiles[] = out.split("\n"); 152 153 for (String heapOutputFile : heapOutputFiles) { 154 try { 155 outputFile = mTestDevice.pullFile(heapOutputFile.trim()); 156 if (outputFile == null) { 157 continue; 158 } 159 outputSource = new FileInputStreamSource(outputFile); 160 listener.testLog(heapOutputFile, LogDataType.TEXT, outputSource); 161 } finally { 162 FileUtil.deleteFile(outputFile); 163 StreamUtil.cancel(outputSource); 164 } 165 } 166 } 167 168 /** 169 * Pull the output files from the device, add it to the logs, and also parse 170 * out the relevant test metrics and report them. 171 */ 172 private void logOutputFiles(ITestInvocationListener listener) 173 throws DeviceNotAvailableException { 174 File outputFile = null; 175 InputStreamSource outputSource = null; 176 177 if (mGetHeapDump) { 178 // Upload all the heap dump files. 179 uploadHeapDumpFiles(listener); 180 } 181 for (String resultFile : mKeyMap.keySet()) { 182 try { 183 outputFile = mTestDevice.pullFileFromExternal(resultFile); 184 185 if (outputFile == null) { 186 return; 187 } 188 189 // Upload a verbatim copy of the output file 190 Log.d(LOG_TAG, String.format( 191 "Sending %d byte file %s into the logosphere!", 192 outputFile.length(), outputFile)); 193 outputSource = new FileInputStreamSource(outputFile); 194 listener.testLog(resultFile, LogDataType.TEXT, outputSource); 195 196 // Parse the output file to upload aggregated metrics 197 parseOutputFile(new FileInputStream(outputFile), listener, resultFile); 198 } catch (IOException e) { 199 Log.e( 200 LOG_TAG, 201 String.format("IOException while reading or parsing output file: %s", e)); 202 } finally { 203 FileUtil.deleteFile(outputFile); 204 StreamUtil.cancel(outputSource); 205 } 206 } 207 } 208 209 /** 210 * Parse the relevant metrics from the Instrumentation test output file 211 */ 212 private void parseOutputFile(InputStream dataStream, 213 ITestInvocationListener listener, String outputFile) { 214 215 // try to parse it 216 String contents; 217 try { 218 contents = StreamUtil.getStringFromStream(dataStream); 219 } catch (IOException e) { 220 Log.e(LOG_TAG, String.format( 221 "Got IOException during test processing: %s", e)); 222 return; 223 } 224 225 List<String> lines = Arrays.asList(contents.split("\n")); 226 ListIterator<String> lineIter = lines.listIterator(); 227 228 String line; 229 String key; 230 String memOut; 231 232 while (lineIter.hasNext()){ 233 line = lineIter.next(); 234 235 // Look for the total diff 236 Matcher m = TOTAL_MEM_DIFF_PATTERN.matcher(line); 237 if (m.matches()){ 238 //First group match with the test key name. 239 key = m.group(1); 240 //Second group match witht the test result. 241 memOut = m.group(2); 242 mRunMetrics.put(key, memOut); 243 } 244 } 245 reportMetrics(listener, outputFile); 246 } 247 248 /** 249 * Report run metrics by creating an empty test run to stick them in 250 * <p /> 251 * Exposed for unit testing 252 */ 253 void reportMetrics(ITestInvocationListener listener, String outputFile) { 254 Log.d(LOG_TAG, String.format("About to report metrics: %s", mRunMetrics)); 255 listener.testRunStarted(mKeyMap.get(outputFile), 0); 256 listener.testRunEnded(0, mRunMetrics); 257 } 258 259 @Override 260 public void setDevice(ITestDevice device) { 261 mTestDevice = device; 262 } 263 264 @Override 265 public ITestDevice getDevice() { 266 return mTestDevice; 267 } 268 } 269