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.config.Option.Importance; 25 import com.android.tradefed.device.DeviceNotAvailableException; 26 import com.android.tradefed.device.ITestDevice; 27 import com.android.tradefed.result.BugreportCollector; 28 import com.android.tradefed.result.BugreportCollector.Freq; 29 import com.android.tradefed.result.BugreportCollector.Noun; 30 import com.android.tradefed.result.BugreportCollector.Relation; 31 import com.android.tradefed.result.FileInputStreamSource; 32 import com.android.tradefed.result.ITestInvocationListener; 33 import com.android.tradefed.result.InputStreamSource; 34 import com.android.tradefed.result.LogDataType; 35 import com.android.tradefed.testtype.IDeviceTest; 36 import com.android.tradefed.testtype.IRemoteTest; 37 import com.android.tradefed.util.FileUtil; 38 import com.android.tradefed.util.RegexTrie; 39 import com.android.tradefed.util.StreamUtil; 40 import com.android.tradefed.util.proto.TfMetricProtoUtil; 41 42 import org.junit.Assert; 43 44 import java.io.File; 45 import java.io.FileInputStream; 46 import java.io.IOException; 47 import java.io.InputStream; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.ListIterator; 53 import java.util.Map; 54 import java.util.concurrent.TimeUnit; 55 56 /** 57 * Runs the Media Player stress test. This test will play the video files under 58 * the /sdcard/samples folder and capture the video playback event statistics in 59 * a text file under /sdcard/PlaybackTestResult.txt 60 * <p/> 61 * Note that this test will not run properly unless /sdcard is mounted and 62 * writable. 63 */ 64 public class MediaPlayerStressTest implements IDeviceTest, IRemoteTest { 65 private static final String LOG_TAG = "MediaPlayerStress"; 66 67 ITestDevice mTestDevice = null; 68 @Option(name = "test-class", importance = Importance.ALWAYS) 69 private String mTestClassName = 70 "com.android.mediaframeworktest.stress.MediaPlayerStressTest"; 71 @Option(name = "metrics-name", importance = Importance.ALWAYS) 72 private String mMetricsRunName = "MediaPlayerStress"; 73 @Option(name = "result-file", importance = Importance.ALWAYS) 74 private String mOutputPath = "PlaybackTestResult.txt"; 75 76 //Max test timeout - 10 hrs 77 private static final int MAX_TEST_TIMEOUT = 10 * 60 * 60 * 1000; 78 79 // Constants for running the tests 80 private static final String TEST_PACKAGE_NAME = "com.android.mediaframeworktest"; 81 private static final String TEST_RUNNER_NAME = ".MediaPlayerStressTestRunner"; 82 83 public RegexTrie<String> mPatternMap = new RegexTrie<>(); 84 MediaPlayerStressTest()85 public MediaPlayerStressTest() { 86 mPatternMap.put("PlaybackPass", "^Total Complete: (\\d+)"); 87 mPatternMap.put("PlaybackCrash", "^Total Error: (\\d+)"); 88 mPatternMap.put("TrackLagging", "^Total Track Lagging: (\\d+)"); 89 mPatternMap.put("BadInterleave", "^Total Bad Interleaving: (\\d+)"); 90 mPatternMap.put("FailedToCompleteWithNoError", 91 "^Total Failed To Complete With No Error: (\\d+)"); 92 } 93 94 @Override run(ITestInvocationListener listener)95 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 96 Assert.assertNotNull(mTestDevice); 97 IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME, 98 TEST_RUNNER_NAME, mTestDevice.getIDevice()); 99 runner.setClassName(mTestClassName); 100 runner.setMaxTimeToOutputResponse(MAX_TEST_TIMEOUT, TimeUnit.MILLISECONDS); 101 102 BugreportCollector bugListener = new BugreportCollector(listener, 103 mTestDevice); 104 bugListener.addPredicate(BugreportCollector.AFTER_FAILED_TESTCASES); 105 bugListener.setDescriptiveName("media_player_stress_test"); 106 bugListener.addPredicate(new BugreportCollector.Predicate( 107 Relation.AFTER, Freq.EACH, Noun.TESTRUN)); 108 109 mTestDevice.runInstrumentationTests(runner, bugListener); 110 111 logOutputFile(listener); 112 cleanResultFile(); 113 } 114 115 /** 116 * Clean up the test result file from test run 117 */ cleanResultFile()118 private void cleanResultFile() throws DeviceNotAvailableException { 119 String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 120 mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, mOutputPath)); 121 } 122 123 /** 124 * Pull the output file from the device, add it to the logs, and also parse 125 * out the relevant test metrics and report them. 126 */ logOutputFile(ITestInvocationListener listener)127 private void logOutputFile(ITestInvocationListener listener) 128 throws DeviceNotAvailableException { 129 File outputFile = null; 130 InputStreamSource outputSource = null; 131 try { 132 outputFile = mTestDevice.pullFileFromExternal(mOutputPath); 133 134 if (outputFile == null) { 135 return; 136 } 137 138 // Upload a verbatim copy of the output file 139 Log.d(LOG_TAG, String.format("Sending %d byte file %s into the logosphere!", 140 outputFile.length(), outputFile)); 141 outputSource = new FileInputStreamSource(outputFile); 142 listener.testLog(mOutputPath, LogDataType.TEXT, outputSource); 143 // Parse the output file to upload aggregated metrics 144 parseOutputFile(new FileInputStream(outputFile), listener); 145 } catch (IOException e) { 146 Log.e(LOG_TAG, String.format( 147 "IOException while reading or parsing output file: %s", e)); 148 } finally { 149 FileUtil.deleteFile(outputFile); 150 StreamUtil.cancel(outputSource); 151 } 152 } 153 154 /** 155 * Parse the relevant metrics from the Instrumentation test output file 156 */ parseOutputFile(InputStream dataStream, ITestInvocationListener listener)157 private void parseOutputFile(InputStream dataStream, 158 ITestInvocationListener listener) { 159 Map<String, String> runMetrics = new HashMap<>(); 160 161 // try to parse it 162 String contents; 163 try { 164 contents = StreamUtil.getStringFromStream(dataStream); 165 } catch (IOException e) { 166 Log.e(LOG_TAG, String.format( 167 "Got IOException during test processing: %s", e)); 168 return; 169 } 170 171 List<String> lines = Arrays.asList(contents.split("\n")); 172 ListIterator<String> lineIter = lines.listIterator(); 173 String line; 174 while (lineIter.hasNext()) { 175 line = lineIter.next(); 176 List<List<String>> capture = new ArrayList<>(1); 177 String key = mPatternMap.retrieve(capture, line); 178 if (key != null) { 179 Log.d(LOG_TAG, String.format("Got '%s' and captures '%s'", 180 key, capture.toString())); 181 } else if (line.isEmpty()) { 182 // ignore 183 continue; 184 } else { 185 Log.d(LOG_TAG, String.format("Got unmatched line: %s", line)); 186 continue; 187 } 188 runMetrics.put(key, capture.get(0).get(0)); 189 } 190 reportMetrics(listener, runMetrics); 191 } 192 193 /** 194 * Report run metrics by creating an empty test run to stick them in 195 * <p /> 196 * Exposed for unit testing 197 */ reportMetrics(ITestInvocationListener listener, Map<String, String> metrics)198 void reportMetrics(ITestInvocationListener listener, Map<String, String> metrics) { 199 Log.d(LOG_TAG, String.format("About to report metrics: %s", metrics)); 200 listener.testRunStarted(mMetricsRunName, 0); 201 listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics)); 202 } 203 204 @Override setDevice(ITestDevice device)205 public void setDevice(ITestDevice device) { 206 mTestDevice = device; 207 } 208 209 @Override getDevice()210 public ITestDevice getDevice() { 211 return mTestDevice; 212 } 213 } 214