Home | History | Annotate | Download | only in tests
      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