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