1 /*
2  * Copyright (C) 2012 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.testrunner.IRemoteAndroidTestRunner;
21 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
22 import com.android.tradefed.device.DeviceNotAvailableException;
23 import com.android.tradefed.device.ITestDevice;
24 import com.android.tradefed.log.LogUtil.CLog;
25 import com.android.tradefed.result.BugreportCollector;
26 import com.android.tradefed.result.ITestInvocationListener;
27 import com.android.tradefed.result.InputStreamSource;
28 import com.android.tradefed.result.LogDataType;
29 import com.android.tradefed.testtype.IDeviceTest;
30 import com.android.tradefed.testtype.IRemoteTest;
31 import com.android.tradefed.util.proto.TfMetricProtoUtil;
32 
33 import org.junit.Assert;
34 
35 import java.io.BufferedReader;
36 import java.io.File;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import java.util.HashMap;
40 import java.util.Map;
41 import java.util.regex.Matcher;
42 import java.util.regex.Pattern;
43 
44 public class CameraShotToShotLatencyTest implements IDeviceTest, IRemoteTest {
45 
46     private static final Pattern MEAN_PATTERN =
47             Pattern.compile("(Shot to shot latency - mean:)(\\s*)(\\d+\\.\\d*)");
48     private static final Pattern STANDARD_DEVIATION_PATTERN =
49             Pattern.compile("(Shot to shot latency - standard deviation:)(\\s*)(\\d+\\.\\d*)");
50 
51     private static final String TEST_CLASS_NAME = "com.android.camera.stress.ShotToShotLatency";
52     private static final String TEST_PACKAGE_NAME = "com.google.android.camera.tests";
53     private static final String TEST_RUNNER_NAME = "android.test.InstrumentationTestRunner";
54 
55     private static final String LATENCY_KEY_MEAN = "Shot2ShotLatencyMean";
56     private static final String LATENCY_KEY_SD = "Shot2ShotLatencySD";
57     private static final String TEST_RU = "CameraLatency";
58 
59     private final String mOutputPath = "mediaStressOut.txt";
60     ITestDevice mTestDevice = null;
61 
62     /**
63      * {@inheritDoc}
64      */
65     @Override
run(ITestInvocationListener listener)66     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
67         Assert.assertNotNull(mTestDevice);
68 
69         IRemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(TEST_PACKAGE_NAME,
70                 TEST_RUNNER_NAME, mTestDevice.getIDevice());
71         runner.setClassName(TEST_CLASS_NAME);
72 
73         BugreportCollector bugListener = new BugreportCollector(listener, mTestDevice);
74         bugListener.addPredicate(BugreportCollector.AFTER_FAILED_TESTCASES);
75         bugListener.setDescriptiveName(this.getClass().getName());
76         Assert.assertTrue(mTestDevice.runInstrumentationTests(runner, bugListener));
77 
78         Map<String, String> metrics = parseOutputFile();
79         reportMetrics(bugListener, TEST_RU, metrics);
80         cleanupDevice();
81     }
82 
83     /**
84      * {@inheritDoc}
85      */
86     @Override
setDevice(ITestDevice device)87     public void setDevice(ITestDevice device) {
88         mTestDevice = device;
89     }
90 
91     /**
92      * {@inheritDoc}
93      */
94     @Override
getDevice()95     public ITestDevice getDevice() {
96         return mTestDevice;
97     }
98 
99     /**
100      * Wipes the device's external memory of test collateral from prior runs.
101      * Note that all photos on the test device will be removed.
102      * @throws DeviceNotAvailableException If the device is unavailable or
103      *         something happened while deleting files
104      */
cleanupDevice()105     private void cleanupDevice() throws DeviceNotAvailableException {
106         String extStore = mTestDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
107         mTestDevice.executeShellCommand(String.format("rm -r %s/DCIM", extStore));
108         mTestDevice.executeShellCommand(String.format("rm %s/%s", extStore, mOutputPath));
109     }
110 
111     /**
112      * Parses the output file generated by the underlying instrumentation test
113      * and returns the metrics to the main driver for later reporting.
114      * @return The {@link Map} that contains metrics for the test.
115      * @throws DeviceNotAvailableException If the device is unavailable or
116      *         something happened while deleting files
117      */
parseOutputFile()118     private Map<String, String> parseOutputFile() throws DeviceNotAvailableException {
119         BufferedReader reader = null;
120         File outputFile = null;
121         String lineMean = null, lineSd = null;
122         Matcher m = null;
123         Map<String, String> metrics = new HashMap<String, String>();
124 
125         // Read in data
126         // Output file is only 2 lines and should look something like:
127         // "Shot to shot latency - mean: 1234.5678901"
128         // "Shot to shot latency - standard deviation: 123.45678901"
129         try {
130             outputFile = mTestDevice.pullFileFromExternal(mOutputPath);
131             reader = new BufferedReader(new FileReader(outputFile));
132 
133             lineMean = reader.readLine();
134             lineSd = reader.readLine();
135 
136             if ((lineMean == null) || (lineSd == null)) {
137                 CLog.e(String.format("Unable to find output data; hit EOF: \nmean:%s\nsd:%s",
138                         lineMean, lineSd));
139             } else {
140                 m = MEAN_PATTERN.matcher(lineMean);
141                 if (m.matches()) {
142                     metrics.put(LATENCY_KEY_MEAN, m.group(3));
143                 } else {
144                     CLog.e(String.format("Unable to find mean: %s", lineMean));
145                 }
146 
147                 m = STANDARD_DEVIATION_PATTERN.matcher(lineSd);
148                 if (m.matches()) {
149                     metrics.put(LATENCY_KEY_SD, m.group(3));
150                 } else {
151                     CLog.e(String.format("Unable to find standard deviation: %s", lineSd));
152                 }
153             }
154         } catch (IOException e) {
155             CLog.e(String.format("IOException reading from file: %s", e.toString()));
156         } finally {
157             if (reader != null) {
158                 try {
159                     reader.close();
160                 } catch (IOException e) {
161                     CLog.e(String.format("IOException closing file: %s", e.toString()));
162                 }
163             }
164         }
165 
166         return metrics;
167     }
168 
169     /**
170      * Report run metrics by creating an empty test run to stick them in.
171      * @param listener The {@link ITestInvocationListener} of test results
172      * @param runName The test name
173      * @param metrics The {@link Map} that contains metrics for the given test
174      */
reportMetrics(ITestInvocationListener listener, String runName, Map<String, String> metrics)175     private void reportMetrics(ITestInvocationListener listener, String runName,
176             Map<String, String> metrics) {
177         InputStreamSource bugreport = mTestDevice.getBugreport();
178         listener.testLog("bugreport", LogDataType.BUGREPORT, bugreport);
179         bugreport.close();
180 
181         CLog.d(String.format("About to report metrics: %s", metrics));
182         listener.testRunStarted(runName, 0);
183         listener.testRunEnded(0, TfMetricProtoUtil.upgradeConvert(metrics));
184     }
185 }
186