1 /* 2 * Copyright (C) 2015 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.tradefed.config.OptionClass; 20 import com.android.tradefed.device.DeviceNotAvailableException; 21 import com.android.tradefed.device.IFileEntry; 22 import com.android.tradefed.log.LogUtil.CLog; 23 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 24 import com.android.tradefed.result.FileInputStreamSource; 25 import com.android.tradefed.result.ITestInvocationListener; 26 import com.android.tradefed.result.LogDataType; 27 import com.android.tradefed.result.TestDescription; 28 import com.android.tradefed.util.FileUtil; 29 30 import java.io.BufferedReader; 31 import java.io.File; 32 import java.io.FileReader; 33 import java.io.IOException; 34 import java.util.HashMap; 35 import java.util.Map; 36 import java.util.Map.Entry; 37 38 /** 39 * Camera2 stress test 40 * Since Camera stress test can drain the battery seriously. Need to split 41 * the test suite into separate test invocation for each test method. 42 * <p/> 43 */ 44 @OptionClass(alias = "camera2-stress") 45 public class Camera2StressTest extends CameraTestBase { 46 47 private static final String RESULT_FILE = "/sdcard/camera-out/stress.txt"; 48 private static final String FAILURE_SCREENSHOT_DIR = "/sdcard/camera-screenshot/"; 49 private static final String KEY_NUM_ATTEMPTS = "numAttempts"; 50 private static final String KEY_ITERATION = "iteration"; 51 52 public Camera2StressTest() { 53 setTestPackage("com.google.android.camera"); 54 setTestClass("com.android.camera.stress.CameraStressTest"); 55 setTestRunner("android.test.InstrumentationTestRunner"); 56 setRuKey("CameraAppStress"); 57 setTestTimeoutMs(6 * 60 * 60 * 1000); // 6 hours 58 setLogcatOnFailure(true); 59 } 60 61 /** 62 * {@inheritDoc} 63 */ 64 @Override 65 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 66 runInstrumentationTest(listener, new CollectingListener(listener)); 67 } 68 69 /** 70 * A listener to collect the output from test run and fatal errors 71 */ 72 private class CollectingListener extends DefaultCollectingListener { 73 74 public CollectingListener(ITestInvocationListener listener) { 75 super(listener); 76 } 77 78 @Override 79 public void testEnded( 80 TestDescription test, long endTime, HashMap<String, Metric> testMetrics) { 81 if (hasTestRunFatalError()) { 82 CLog.v("The instrumentation result not found. Fall back to get the metrics from a " 83 + "log file. errorMsg: %s", getCollectingListener().getErrorMessage()); 84 } 85 // TODO: Will get the additional metrics to file to prevent result loss 86 87 // Don't need to report the KEY_NUM_ATTEMPS to dashboard 88 // Iteration will be read from file 89 testMetrics.remove(KEY_NUM_ATTEMPTS); 90 testMetrics.remove(KEY_ITERATION); 91 92 // add testMethod name to the metric 93 Map<String, String> namedTestMetrics = new HashMap<>(); 94 for (Entry<String, Metric> entry : testMetrics.entrySet()) { 95 namedTestMetrics.put( 96 test.getTestName() + entry.getKey(), 97 entry.getValue().getMeasurements().getSingleString()); 98 } 99 100 // parse the iterations metrics from the stress log files 101 parseLog(test.getTestName(), namedTestMetrics); 102 103 postScreenshotOnFailure(test); 104 super.testEnded(test, endTime, namedTestMetrics); 105 } 106 107 private void postScreenshotOnFailure(TestDescription test) { 108 File tmpDir = null; 109 try { 110 IFileEntry screenshotDir = getDevice().getFileEntry(FAILURE_SCREENSHOT_DIR); 111 if (screenshotDir != null && screenshotDir.isDirectory()) { 112 tmpDir = FileUtil.createTempDir("screenshot"); 113 for (IFileEntry remoteFile : screenshotDir.getChildren(false)) { 114 if (remoteFile.isDirectory()) { 115 continue; 116 } 117 if (!remoteFile.getName().contains(test.getTestName())) { 118 CLog.v("Skipping the screenshot (%s) that doesn't match the current " 119 + "test (%s)", remoteFile.getName(), test.getTestName()); 120 continue; 121 } 122 File screenshot = new File(tmpDir, remoteFile.getName()); 123 if (!getDevice().pullFile(remoteFile.getFullPath(), screenshot)) { 124 CLog.w("Could not pull screenshot: %s", remoteFile.getFullPath()); 125 continue; 126 } 127 testLog( 128 "screenshot_" + screenshot.getName(), 129 LogDataType.PNG, 130 new FileInputStreamSource(screenshot)); 131 } 132 } 133 } catch (DeviceNotAvailableException e) { 134 CLog.e(e); 135 } catch (IOException e) { 136 CLog.e(e); 137 } finally { 138 FileUtil.recursiveDelete(tmpDir); 139 } 140 } 141 142 // Return null if failed to parse the result file or the test didn't even start. 143 private void parseLog(String testName, Map<String, String> testMetrics) { 144 try { 145 File outputFile = FileUtil.createTempFile("stress", ".txt"); 146 getDevice().pullFile(RESULT_FILE, outputFile); 147 if (outputFile == null) { 148 throw new DeviceNotAvailableException(String.format("Failed to pull the result" 149 + "file: %s", RESULT_FILE), getDevice().getSerialNumber()); 150 } 151 BufferedReader reader = new BufferedReader(new FileReader(outputFile)); 152 String line; 153 Map<String, String> resultMap = new HashMap<>(); 154 155 // Parse results from log file that contain the key-value pairs. 156 // eg. "numAttempts=10|iteration=9" 157 try { 158 while ((line = reader.readLine()) != null) { 159 String[] pairs = line.split("\\|"); 160 for (String pair : pairs) { 161 String[] keyValue = pair.split("="); 162 // Each should be a pair of key and value. 163 String key = keyValue[0].trim(); 164 String value = keyValue[1].trim(); 165 resultMap.put(key, value); 166 CLog.v("%s: %s", key, value); 167 } 168 } 169 } finally { 170 reader.close(); 171 } 172 173 // Fail if a stress test doesn't start. 174 if (0 == Integer.parseInt(resultMap.get(KEY_NUM_ATTEMPTS))) { 175 CLog.w("Failed to start stress tests. test setup configured incorrectly?"); 176 return; 177 } 178 // Post the number of iterations only with the test name as key. 179 testMetrics.put(testName, resultMap.get(KEY_ITERATION)); 180 } catch (IOException e) { 181 CLog.w("Couldn't parse the output log file:"); 182 CLog.e(e); 183 } catch (DeviceNotAvailableException e) { 184 CLog.w("Could not pull file: %s, error:", RESULT_FILE); 185 CLog.e(e); 186 } catch (NumberFormatException e) { 187 CLog.w("Could not find the key in file: %s, error:", KEY_NUM_ATTEMPTS); 188 CLog.e(e); 189 } 190 } 191 } 192 } 193