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