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