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.CollectingTestListener;
     27 import com.android.tradefed.result.FileInputStreamSource;
     28 import com.android.tradefed.result.ITestInvocationListener;
     29 import com.android.tradefed.result.InputStreamSource;
     30 import com.android.tradefed.result.LogDataType;
     31 import com.android.tradefed.testtype.IDeviceTest;
     32 import com.android.tradefed.testtype.IRemoteTest;
     33 import com.android.tradefed.util.FileUtil;
     34 import com.android.tradefed.util.RegexTrie;
     35 import com.android.tradefed.util.StreamUtil;
     36 
     37 import junit.framework.TestCase;
     38 
     39 import org.junit.Assert;
     40 
     41 import java.io.ByteArrayInputStream;
     42 import java.io.File;
     43 import java.io.FileInputStream;
     44 import java.io.IOException;
     45 import java.io.InputStream;
     46 import java.util.ArrayList;
     47 import java.util.Arrays;
     48 import java.util.HashMap;
     49 import java.util.List;
     50 import java.util.ListIterator;
     51 import java.util.Map;
     52 import java.util.Set;
     53 import java.util.concurrent.TimeUnit;
     54 
     55 /**
     56  * Runs the Camera stress testcases.
     57  * FIXME: more details
     58  * <p/>
     59  * Note that this test will not run properly unless /sdcard is mounted and writable.
     60  */
     61 public class CameraStressTest implements IDeviceTest, IRemoteTest {
     62     private static final String LOG_TAG = "CameraStressTest";
     63 
     64     ITestDevice mTestDevice = null;
     65 
     66     // Constants for running the tests
     67     private static final String TEST_PACKAGE_NAME = "com.google.android.camera.tests";
     68     private static final String TEST_RUNNER = "com.android.camera.stress.CameraStressTestRunner";
     69 
     70     //Max test timeout - 3 hrs
     71     private static final int MAX_TEST_TIMEOUT = 3 * 60 * 60 * 1000;
     72 
     73     private final String mOutputPath = "mediaStressOut.txt";
     74 
     75     /**
     76      * Stores the test cases that we should consider running.
     77      *
     78      * <p>This currently consists of "startup" and "latency"
     79      */
     80     private List<TestInfo> mTestCases = new ArrayList<>();
     81 
     82     // Options for the running the gCam test
     83     @Option(name = "gCam", description = "Run gCam back image capture test")
     84     private boolean mGcam = false;
     85 
     86     /**
     87      * A struct that contains useful info about the tests to run
     88      */
     89     static class TestInfo {
     90         public String mTestName = null;
     91         public String mClassName = null;
     92         public String mTestMetricsName = null;
     93         public Map<String, String> mInstrumentationArgs = new HashMap<>();
     94         public RegexTrie<String> mPatternMap = new RegexTrie<>();
     95 
     96         @Override
     97         public String toString() {
     98             return String.format("TestInfo: name(%s) class(%s) metric(%s) patterns(%s)", mTestName,
     99                     mClassName, mTestMetricsName, mPatternMap);
    100         }
    101     }
    102 
    103     /**
    104      * Set up the pattern map for parsing output files
    105      * <p/>
    106      * Exposed for unit meta-testing
    107      */
    108     static RegexTrie<String> getPatternMap() {
    109         RegexTrie<String> patMap = new RegexTrie<>();
    110         patMap.put("SwitchPreview", "^Camera Switch Mode:");
    111 
    112         // For versions of the on-device test that don't differentiate between front and back camera
    113         patMap.put("ImageCapture", "^Camera Image Capture");
    114         patMap.put("VideoRecording", "^Camera Video Capture");
    115 
    116         // For versions that do differentiate
    117         patMap.put("FrontImageCapture", "^Front Camera Image Capture");
    118         patMap.put("ImageCapture", "^Back Camera Image Capture");
    119         patMap.put("FrontVideoRecording", "^Front Camera Video Capture");
    120         patMap.put("VideoRecording", "^Back Camera Video Capture");
    121 
    122         // Actual metrics to collect for a given key
    123         patMap.put("loopCount", "^No of loops :(\\d+)");
    124         patMap.put("iters", "^loop:.+,(\\d+)");
    125 
    126         return patMap;
    127     }
    128 
    129     /**
    130      * Set up the configurations for the test cases we want to run
    131      */
    132     private void testInfoSetup() {
    133         RegexTrie<String> patMap = getPatternMap();
    134         TestInfo t = new TestInfo();
    135 
    136         if (mGcam) {
    137             // Back Image capture stress test for gCam
    138             t.mTestName = "testBackImageCapture";
    139             t.mClassName = "com.android.camera.stress.ImageCapture";
    140             t.mTestMetricsName = "GCamApplicationStress";
    141             t.mInstrumentationArgs.put("image_iterations", Integer.toString(100));
    142             t.mPatternMap = patMap;
    143             mTestCases.add(t);
    144 
    145         } else {
    146             // Image capture stress test
    147             t.mTestName = "imagecap";
    148             t.mClassName = "com.android.camera.stress.ImageCapture";
    149             t.mTestMetricsName = "CameraApplicationStress";
    150             t.mInstrumentationArgs.put("image_iterations", Integer.toString(100));
    151             t.mPatternMap = patMap;
    152             mTestCases.add(t);
    153 
    154             // Image capture stress test
    155             t = new TestInfo();
    156             t.mTestName = "videocap";
    157             t.mClassName = "com.android.camera.stress.VideoCapture";
    158             t.mTestMetricsName = "CameraApplicationStress";
    159             t.mInstrumentationArgs.put("video_iterations", Integer.toString(100));
    160             t.mPatternMap = patMap;
    161             mTestCases.add(t);
    162 
    163             // "SwitchPreview" stress test
    164             t = new TestInfo();
    165             t.mTestName = "switch";
    166             t.mClassName = "com.android.camera.stress.SwitchPreview";
    167             t.mTestMetricsName = "CameraApplicationStress";
    168             t.mPatternMap = patMap;
    169             mTestCases.add(t);
    170         }
    171     }
    172 
    173     @Override
    174     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    175         Assert.assertNotNull(mTestDevice);
    176         testInfoSetup();
    177         for (TestInfo test : mTestCases) {
    178             cleanTmpFiles();
    179             executeTest(test, listener);
    180             logOutputFiles(test, listener);
    181         }
    182 
    183         cleanTmpFiles();
    184     }
    185 
    186     private void executeTest(TestInfo test, ITestInvocationListener listener)
    187             throws DeviceNotAvailableException {
    188         IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME,
    189                 TEST_RUNNER, mTestDevice.getIDevice());
    190         CollectingTestListener auxListener = new CollectingTestListener();
    191 
    192         runner.setClassName(test.mClassName);
    193         runner.setMaxTimeToOutputResponse(MAX_TEST_TIMEOUT, TimeUnit.MILLISECONDS);
    194         if (mGcam){
    195             runner.setMethodName(test.mClassName, test.mTestName);
    196         }
    197 
    198         Set<String> argumentKeys = test.mInstrumentationArgs.keySet();
    199         for (String s : argumentKeys) {
    200             runner.addInstrumentationArg(s, test.mInstrumentationArgs.get(s));
    201         }
    202 
    203         mTestDevice.runInstrumentationTests(runner, listener, auxListener);
    204 
    205         // Grab a bugreport if warranted
    206         if (auxListener.hasFailedTests()) {
    207             Log.e(LOG_TAG, String.format("Grabbing bugreport after test '%s' finished with " +
    208                     "%d failures.", test.mTestName, auxListener.getNumAllFailedTests()));
    209             InputStreamSource bugreport = mTestDevice.getBugreport();
    210             listener.testLog(String.format("bugreport-%s.txt", test.mTestName),
    211                     LogDataType.BUGREPORT, bugreport);
    212             bugreport.cancel();
    213         }
    214     }
    215 
    216     /**
    217      * Clean up temp files from test runs
    218      * <p />
    219      * Note that all photos on the test device will be removed
    220      */
    221     private void cleanTmpFiles() throws DeviceNotAvailableException {
    222         String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
    223         mTestDevice.executeShellCommand(String.format("rm -r %s/DCIM/Camera", extStore));
    224         mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, mOutputPath));
    225     }
    226 
    227     /**
    228      * Pull the output file from the device, add it to the logs, and also parse out the relevant
    229      * test metrics and report them.  Additionally, pull the memory file (if it exists) and report
    230      * it.
    231      */
    232     private void logOutputFiles(TestInfo test, ITestInvocationListener listener)
    233             throws DeviceNotAvailableException {
    234         File outputFile = null;
    235         InputStreamSource outputSource = null;
    236         try {
    237             outputFile = mTestDevice.pullFileFromExternal(mOutputPath);
    238 
    239             if (outputFile == null) {
    240                 return;
    241             }
    242 
    243             // Upload a verbatim copy of the output file
    244             Log.d(LOG_TAG, String.format("Sending %d byte file %s into the logosphere!",
    245                     outputFile.length(), outputFile));
    246             outputSource = new FileInputStreamSource(outputFile);
    247             listener.testLog(String.format("output-%s.txt", test.mTestName), LogDataType.TEXT,
    248                     outputSource);
    249 
    250             // Parse the output file to upload aggregated metrics
    251             parseOutputFile(test, new FileInputStream(outputFile), listener);
    252         } catch (IOException e) {
    253             Log.e(LOG_TAG, String.format("IOException while reading or parsing output file: %s", e));
    254         } finally {
    255             FileUtil.deleteFile(outputFile);
    256             StreamUtil.cancel(outputSource);
    257         }
    258     }
    259 
    260     /**
    261      * Parse the relevant metrics from the Instrumentation test output file
    262      */
    263     private void parseOutputFile(TestInfo test, InputStream dataStream,
    264             ITestInvocationListener listener) {
    265         Map<String, String> runMetrics = new HashMap<>();
    266 
    267         String contents;
    268         try {
    269             contents = StreamUtil.getStringFromStream(dataStream);
    270         } catch (IOException e) {
    271             Log.e(LOG_TAG, String.format("Got IOException during %s test processing: %s",
    272                     test.mTestName, e));
    273             return;
    274         }
    275 
    276         String key = null;
    277         Integer countExpected = null;
    278         Integer countActual = null;
    279 
    280         List<String> lines = Arrays.asList(contents.split("\n"));
    281         ListIterator<String> lineIter = lines.listIterator();
    282         String line;
    283         while (lineIter.hasNext()) {
    284             line = lineIter.next();
    285             List<List<String>> capture = new ArrayList<>(1);
    286             String pattern = test.mPatternMap.retrieve(capture, line);
    287             if (pattern != null) {
    288                 if ("loopCount".equals(pattern)) {
    289                     // First capture in first (only) string
    290                     countExpected = Integer.parseInt(capture.get(0).get(0));
    291                 } else if ("iters".equals(pattern)) {
    292                     // First capture in first (only) string
    293                     countActual = Integer.parseInt(capture.get(0).get(0));
    294 
    295                     if (countActual != null) {
    296                         // countActual starts counting at 0
    297                         countActual += 1;
    298                     }
    299                 } else {
    300                     // Assume that the pattern is the name of a key
    301 
    302                     // commit, if there was a previous key
    303                     if (key != null) {
    304                         int value = coalesceLoopCounts(countActual, countExpected);
    305                         runMetrics.put(key, Integer.toString(value));
    306                     }
    307 
    308                     key = pattern;
    309                     countExpected = null;
    310                     countActual = null;
    311                 }
    312 
    313                 Log.d(LOG_TAG, String.format("Got %s key '%s' and captures '%s'",
    314                         test.mTestName, key, capture.toString()));
    315             } else if (line.isEmpty()) {
    316                 // ignore
    317                 continue;
    318             } else {
    319                 Log.e(LOG_TAG, String.format("Got unmatched line: %s", line));
    320                 continue;
    321             }
    322 
    323             // commit the final key, if there was one
    324             if (key != null) {
    325                 int value = coalesceLoopCounts(countActual, countExpected);
    326                 runMetrics.put(key, Integer.toString(value));
    327             }
    328         }
    329 
    330         reportMetrics(listener, test, runMetrics);
    331     }
    332 
    333     /**
    334      * Given an actual and an expected iteration count, determine a single metric to report.
    335      */
    336     private int coalesceLoopCounts(Integer actual, Integer expected) {
    337         if (expected == null || expected <= 0) {
    338             return -1;
    339         } else if (actual == null) {
    340             return expected;
    341         } else {
    342             return actual;
    343         }
    344     }
    345 
    346     /**
    347      * Report run metrics by creating an empty test run to stick them in
    348      * <p />
    349      * Exposed for unit testing
    350      */
    351     void reportMetrics(ITestInvocationListener listener, TestInfo test,
    352             Map<String, String> metrics) {
    353         // Create an empty testRun to report the parsed runMetrics
    354         Log.e(LOG_TAG, String.format("About to report metrics for %s: %s", test.mTestMetricsName,
    355                 metrics));
    356         listener.testRunStarted(test.mTestMetricsName, 0);
    357         listener.testRunEnded(0, metrics);
    358     }
    359 
    360     @Override
    361     public void setDevice(ITestDevice device) {
    362         mTestDevice = device;
    363     }
    364 
    365     @Override
    366     public ITestDevice getDevice() {
    367         return mTestDevice;
    368     }
    369 
    370     /**
    371      * A meta-test to ensure that bits of the BluetoothStressTest are working properly
    372      */
    373     public static class MetaTest extends TestCase {
    374         private CameraStressTest mTestInstance = null;
    375 
    376         private TestInfo mTestInfo = null;
    377 
    378         private TestInfo mReportedTestInfo = null;
    379         private Map<String, String> mReportedMetrics = null;
    380 
    381         private static String join(String... pieces) {
    382             StringBuilder sb = new StringBuilder();
    383             for (String piece : pieces) {
    384                 sb.append(piece);
    385                 sb.append("\n");
    386             }
    387             return sb.toString();
    388         }
    389 
    390         @Override
    391         public void setUp() throws Exception {
    392             mTestInstance = new CameraStressTest() {
    393                 @Override
    394                 void reportMetrics(ITestInvocationListener l, TestInfo test,
    395                         Map<String, String> metrics) {
    396                     mReportedTestInfo = test;
    397                     mReportedMetrics = metrics;
    398                 }
    399             };
    400 
    401             // Image capture stress test
    402             mTestInfo = new TestInfo();
    403             TestInfo t = mTestInfo;  // for convenience
    404             t.mTestName = "capture";
    405             t.mClassName = "com.android.camera.stress.ImageCapture";
    406             t.mTestMetricsName = "camera_application_stress";
    407             t.mPatternMap = getPatternMap();
    408         }
    409 
    410         /**
    411          * Make sure that parsing works for devices sending output in the old format
    412          */
    413         public void testParse_old() throws Exception {
    414             String output = join(
    415                     "Camera Image Capture",
    416                     "No of loops :100",
    417                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    418                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 " +
    419                         ",36 ,37 ,38 ,39 ,40 ,41 ,42",
    420                     "Camera Video Capture",
    421                     "No of loops :100",
    422                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    423                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 " +
    424                         ",36 ,37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 " +
    425                         ",53 ,54 ,55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 " +
    426                         ",70 ,71 ,72 ,73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 " +
    427                         ",87 ,88 ,89 ,90 ,91 ,92 ,93 ,94 ,95 ,96 ,97 ,98 ,99",
    428                     "Camera Switch Mode:",
    429                     "No of loops :200",
    430                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13");
    431 
    432             InputStream iStream = new ByteArrayInputStream(output.getBytes());
    433             mTestInstance.parseOutputFile(mTestInfo, iStream, null);
    434             assertEquals(mTestInfo, mReportedTestInfo);
    435             assertNotNull(mReportedMetrics);
    436             Log.e(LOG_TAG, String.format("Got reported metrics: %s", mReportedMetrics.toString()));
    437             assertEquals(3, mReportedMetrics.size());
    438             assertEquals("43", mReportedMetrics.get("ImageCapture"));
    439             assertEquals("100", mReportedMetrics.get("VideoRecording"));
    440             assertEquals("14", mReportedMetrics.get("SwitchPreview"));
    441         }
    442 
    443         /**
    444          * Make sure that parsing works for devices sending output in the new format
    445          */
    446         public void testParse_new() throws Exception {
    447             String output = join(
    448                     "Camera Stress Test result",
    449                     "/folder/subfolder/data/CameraStressTest_git_honeycomb-mr1-release_" +
    450                         "1700614441c02617_109535_CameraStressOut.txt",
    451                     "Back Camera Image Capture",
    452                     "No of loops :100",
    453                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    454                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 " +
    455                         ",37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 ,53 ,54 " +
    456                         ",55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 " +
    457                         ",73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 " +
    458                         ",91 ,92 ,93 ,94 ,95 ,96 ,97 ,98 ,99",
    459                     "Front Camera Image Capture",
    460                     "No of loops :100",
    461                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    462                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 " +
    463                         ",37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 ,53 ,54 " +
    464                         ",55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 " +
    465                         ",73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 " +
    466                         ",91 ,92 ,93 ,94 ,95 ,96 ,97 ,98",
    467                     "Back Camera Video Capture",
    468                     "No of loops :100",
    469                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    470                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 " +
    471                         ",37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 ,53 ,54 " +
    472                         ",55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 " +
    473                         ",73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 " +
    474                         ",91 ,92 ,93 ,94 ,95 ,96 ,97",
    475                     "Front Camera Video Capture",
    476                     "No of loops :100",
    477                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    478                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 " +
    479                         ",37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 ,53 ,54 " +
    480                         ",55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 " +
    481                         ",73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 " +
    482                         ",91 ,92 ,93 ,94 ,95 ,96 ,97 ,98 ,99",
    483                     "Camera Switch Mode:",
    484                     "No of loops :200",
    485                     "loop:  ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 " +
    486                         ",19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,31 ,32 ,33 ,34 ,35 ,36 " +
    487                         ",37 ,38 ,39 ,40 ,41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,50 ,51 ,52 ,53 ,54 " +
    488                         ",55 ,56 ,57 ,58 ,59 ,60 ,61 ,62 ,63 ,64 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 " +
    489                         ",73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 ,83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 " +
    490                         ",91 ,92 ,93 ,94 ,95 ,96 ,97 ,98 ,99 ,100 ,101 ,102 ,103 ,104 ,105 ,106 " +
    491                         ",107 ,108 ,109 ,110 ,111 ,112 ,113 ,114 ,115 ,116 ,117 ,118 ,119 ,120 " +
    492                         ",121 ,122 ,123 ,124 ,125 ,126 ,127 ,128 ,129 ,130 ,131 ,132 ,133 ,134 " +
    493                         ",135 ,136 ,137 ,138 ,139 ,140 ,141 ,142 ,143 ,144 ,145 ,146 ,147 ,148 " +
    494                         ",149 ,150 ,151 ,152 ,153 ,154 ,155 ,156 ,157 ,158 ,159 ,160 ,161 ,162 " +
    495                         ",163 ,164 ,165 ,166 ,167 ,168 ,169 ,170 ,171 ,172 ,173 ,174 ,175 ,176 " +
    496                         ",177 ,178 ,179 ,180 ,181 ,182 ,183 ,184 ,185 ,186 ,187 ,188 ,189 ,190 " +
    497                         ",191 ,192 ,193 ,194 ,195 ,196 ,197 ,198 ,199");
    498 
    499             InputStream iStream = new ByteArrayInputStream(output.getBytes());
    500             mTestInstance.parseOutputFile(mTestInfo, iStream, null);
    501             assertEquals(mTestInfo, mReportedTestInfo);
    502             assertNotNull(mReportedMetrics);
    503             Log.e(LOG_TAG, String.format("Got reported metrics: %s", mReportedMetrics.toString()));
    504             assertEquals(5, mReportedMetrics.size());
    505             assertEquals("100", mReportedMetrics.get("ImageCapture"));
    506             assertEquals("99", mReportedMetrics.get("FrontImageCapture"));
    507             assertEquals("98", mReportedMetrics.get("VideoRecording"));
    508             assertEquals("100", mReportedMetrics.get("FrontVideoRecording"));
    509             assertEquals("200", mReportedMetrics.get("SwitchPreview"));
    510         }
    511     }
    512 }
    513 
    514