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.tradefed.testtype;
18 
19 import com.android.tradefed.config.Option;
20 import com.android.tradefed.config.OptionClass;
21 import com.android.tradefed.device.DeviceNotAvailableException;
22 import com.android.tradefed.log.LogUtil.CLog;
23 import com.android.tradefed.result.CollectingTestListener;
24 import com.android.tradefed.result.FileInputStreamSource;
25 import com.android.tradefed.result.ITestInvocationListener;
26 import com.android.tradefed.result.InputStreamSource;
27 import com.android.tradefed.result.LogDataType;
28 import com.android.tradefed.result.ResultForwarder;
29 import com.android.tradefed.result.TestRunResult;
30 import com.android.tradefed.util.FileUtil;
31 import com.android.tradefed.util.RunUtil;
32 
33 import java.io.File;
34 import java.util.Map;
35 
36 /**
37  * A Test that runs an instrumentation test package on a given device and
38  * generates the code coverage report. Requires an emma instrumented
39  * application.
40  */
41 @OptionClass(alias = "code-coverage")
42 public class CodeCoverageTest extends InstrumentationTest {
43 
44     @Option(name = "coverage-file",
45             description = "Optional custom emma coverage file path. " +
46                     "If unspecified, will use package name.")
47     private String mCoverageFile = null;
48 
49     public static final String COVERAGE_REMOTE_FILE_LABEL = "coverageFilePath";
50 
51     @Override
run(final ITestInvocationListener listener)52     public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException {
53         // Disable rerun mode, we want to stop the tests as soon as we fail.
54         super.setRerunMode(false);
55         // Force generation of emma coverage file to true and set up coverage
56         // file path.
57         super.addInstrumentationArg("coverage", "true");
58         if (mCoverageFile != null) {
59             super.addInstrumentationArg("coverageFile", mCoverageFile);
60         }
61 
62         CollectingTestListener testCoverageFile = new CollectingTestListener();
63 
64         // Run instrumentation tests.
65         super.run(new ResultForwarder(listener, testCoverageFile));
66 
67         // If coverage file path was not set explicitly before test run, fetch
68         // it from the
69         // instrumentation out.
70         if (mCoverageFile == null) {
71             mCoverageFile = fetchCoverageFilePath(testCoverageFile);
72         }
73         CLog.d("Coverage file at %s", mCoverageFile);
74         File coverageFile = null;
75         try {
76             if (getDevice().doesFileExist(mCoverageFile)) {
77                 coverageFile = getDevice().pullFile(mCoverageFile);
78                 if (coverageFile != null) {
79                     CLog.d("coverage file from device: %s", coverageFile.getAbsolutePath());
80                     try (FileInputStreamSource source = new FileInputStreamSource(coverageFile)) {
81                         listener.testLog(
82                                 getPackageName() + "_runtime_coverage",
83                                 LogDataType.COVERAGE,
84                                 source);
85                     }
86                 }
87             } else {
88                 CLog.w("Missing coverage file %s. Did test crash?", mCoverageFile);
89                 RunUtil.getDefault().sleep(2000);
90                 // grab logcat snapshot when this happens
91                 try (InputStreamSource s = getDevice().getLogcat(500 * 1024)) {
92                     listener.testLog(
93                             getPackageName() + "_coverage_crash_" + getTestSize(),
94                             LogDataType.LOGCAT,
95                             s);
96                 }
97             }
98         } finally {
99             if (coverageFile != null) {
100                 FileUtil.deleteFile(coverageFile);
101             }
102         }
103     }
104 
105     /**
106      * Returns the runtime coverage file path from instrumentation test metrics.
107      */
fetchCoverageFilePath(CollectingTestListener listener)108     private String fetchCoverageFilePath(CollectingTestListener listener) {
109         TestRunResult runResult = listener.getCurrentRunResults();
110         Map<String, String> metrics = runResult.getRunMetrics();
111         return metrics.get(COVERAGE_REMOTE_FILE_LABEL);
112     }
113 }
114