1 /*
2  * Copyright (C) 2018 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.tradefed.device.metric;
18 
19 import com.android.annotations.VisibleForTesting;
20 import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
21 import com.android.tradefed.build.IBuildInfo;
22 import com.android.tradefed.config.OptionClass;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.device.ITestDevice;
25 import com.android.tradefed.log.LogUtil.CLog;
26 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
27 import com.android.tradefed.targetprep.VtsCoveragePreparer;
28 import com.android.tradefed.util.CommandResult;
29 import com.android.tradefed.util.CommandStatus;
30 import com.android.tradefed.util.RunInterruptedException;
31 import com.android.tradefed.util.VtsPythonRunnerHelper;
32 
33 import java.io.File;
34 import java.io.FileNotFoundException;
35 import java.util.Map;
36 /**
37  * A {@link IMetricCollector} that enables vts coverage measurement during a
38  * test and generates the coverage report after the test run.
39  */
40 @OptionClass(alias = "vts-coverage-collector")
41 public class VtsCoverageCollector extends BaseDeviceMetricCollector {
42     static final long BASE_TIMEOUT = 1000 * 60 * 20; // timeout for fetching artifacts
43 
44     private VtsPythonRunnerHelper mPythonRunnerHelper = null;
45     @Override
onTestRunStart(DeviceMetricData testData)46     public void onTestRunStart(DeviceMetricData testData) {
47         for (ITestDevice device : getDevices()) {
48             try {
49                 device.executeShellCommand("rm -rf /data/misc/trace/*");
50             } catch (DeviceNotAvailableException e) {
51                 CLog.e("Failed to cleanup existing traces: " + e.toString());
52             }
53         }
54     }
55 
56     @Override
onTestRunEnd(DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics)57     public void onTestRunEnd(DeviceMetricData testData,
58             final Map<String, Metric> currentTestCaseMetrics) throws RunInterruptedException {
59         String moduleName = getRunName().replace(' ', '_');
60         CLog.i("Test module name: " + moduleName);
61         IBuildInfo buildInfo = getBuildInfos().get(0);
62         if (buildInfo == null) {
63             CLog.e("Could not get build Info.");
64             return;
65         }
66         if (mPythonRunnerHelper == null) {
67             File workingDir = null;
68             VtsCompatibilityInvocationHelper invocationHelper = createInvocationHelper();
69             try {
70                 workingDir = invocationHelper.getTestsDir();
71             } catch (FileNotFoundException e) {
72                 CLog.e("VtsCompatibilityInvocationHelper cannot find test case directory. "
73                         + "Command working directory not set.");
74             }
75             mPythonRunnerHelper = new VtsPythonRunnerHelper(buildInfo, workingDir);
76         }
77         for (ITestDevice device : getDevices()) {
78             String serial = device.getSerialNumber();
79             String gcovDirPath = getGcoveResrouceDir(buildInfo, device);
80             if (gcovDirPath == null) {
81                 CLog.e("Could not get gcov resource dir path.");
82                 return;
83             }
84             String coverage_report_dir = buildInfo.getBuildAttributes().get("coverage_report_path");
85             if (coverage_report_dir == null) {
86                 CLog.e("Must specify the directory to store the coverage report.");
87                 return;
88             }
89             File local_coverage_report_dir = new File(coverage_report_dir, moduleName);
90 
91             String cmdString = "python"
92                     + " -m vts.utils.python.coverage.coverage_utils get_coverage --serial " + serial
93                     + " --gcov_rescource_path " + gcovDirPath + " --report_path "
94                     + local_coverage_report_dir.getAbsolutePath() + " --report_prefix "
95                     + moduleName;
96             String[] cmd = cmdString.split("\\s+");
97             CommandResult commandResult = new CommandResult();
98             String interruptMessage =
99                     mPythonRunnerHelper.runPythonRunner(cmd, commandResult, BASE_TIMEOUT);
100             if (commandResult == null || commandResult.getStatus() != CommandStatus.SUCCESS) {
101                 CLog.e("Could not get coverage data.");
102             }
103             if (interruptMessage != null) {
104                 throw new RunInterruptedException(interruptMessage);
105             }
106         }
107     }
108 
109     @VisibleForTesting
getGcoveResrouceDir(IBuildInfo buildInfo, ITestDevice device)110     String getGcoveResrouceDir(IBuildInfo buildInfo, ITestDevice device) {
111         File gcovDir = buildInfo.getFile(VtsCoveragePreparer.getGcovResourceDirKey(device));
112         if (gcovDir != null) {
113             return gcovDir.getAbsolutePath();
114         }
115         return null;
116     }
117 
118     @VisibleForTesting
setPythonRunnerHelper(VtsPythonRunnerHelper pythonRunnerHelper)119     void setPythonRunnerHelper(VtsPythonRunnerHelper pythonRunnerHelper) {
120         mPythonRunnerHelper = pythonRunnerHelper;
121     }
122 
123     /**
124      * Creates a {@link VtsCompatibilityInvocationHelper} to get the working directory.
125      */
126     @VisibleForTesting
createInvocationHelper()127     protected VtsCompatibilityInvocationHelper createInvocationHelper() {
128         return new VtsCompatibilityInvocationHelper();
129     }
130 }
131