1 /*
2  * Copyright (C) 2011 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.cts.tradefed.testtype;
18 
19 import com.android.cts.tradefed.build.CtsBuildHelper;
20 import com.android.ddmlib.testrunner.ITestRunListener;
21 import com.android.tradefed.build.IBuildInfo;
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.ITestInvocationListener;
26 import com.android.tradefed.testtype.IAbi;
27 import com.android.tradefed.testtype.IBuildReceiver;
28 import com.android.tradefed.testtype.IDeviceTest;
29 import com.android.tradefed.testtype.IRemoteTest;
30 
31 import java.io.File;
32 import java.util.ArrayList;
33 import java.util.List;
34 
35 /**
36  * Test runner for native gTests.
37  *
38  * TODO: This is similar to Tradefed's existing GTest, but it doesn't confirm
39  *       each directory segment exists using ddmlib's file service. This was
40  *       a problem since /data is not visible on a user build, but it is
41  *       executable. It's also a lot more verbose when it comes to errors.
42  */
43 public class GeeTest implements IBuildReceiver, IDeviceTest, IRemoteTest {
44 
45     private static final String NATIVE_TESTS_DIRECTORY = "/data/local/tmp/cts-native-tests";
46     private static final String NATIVE_TESTS_DIRECTORY_TMP = "/data/local/tmp";
47     private static final String ANDROID_PATH_SEPARATOR = "/";
48     private static final String GTEST_FLAG_FILTER = "--gtest_filter=";
49 
50     private int mMaxTestTimeMs = 1 * 60 * 1000;
51 
52     private CtsBuildHelper mCtsBuild;
53     private ITestDevice mDevice;
54     private IAbi mAbi;
55     private String mExeName;
56 
57     private final String mPackageName;
58 
59     private String mPositiveFilters = "";
60     private String mNegativeFilters = "";
61 
GeeTest(String packageName, String exeName)62     public GeeTest(String packageName, String exeName) {
63         mPackageName = packageName;
64         mExeName = exeName;
65     }
66 
setPositiveFilters(String positiveFilters)67     public void setPositiveFilters(String positiveFilters) {
68         mPositiveFilters = positiveFilters;
69     }
70 
setNegativeFilters(String negativeFilters)71     public void setNegativeFilters(String negativeFilters) {
72         mNegativeFilters = negativeFilters;
73     }
74 
getGTestFilters()75     protected String getGTestFilters() {
76         // If both filters are empty or null return empty string.
77         if (mPositiveFilters == null && mNegativeFilters == null) {
78             return "";
79         }
80         if (mPositiveFilters.isEmpty() && mNegativeFilters.isEmpty()) {
81             return "";
82         }
83         // Build filter string.
84         StringBuilder sb = new StringBuilder();
85         sb.append(GTEST_FLAG_FILTER);
86         boolean hasPositiveFilters = false;
87         if (mPositiveFilters != null && !mPositiveFilters.isEmpty()) {
88             sb.append(mPositiveFilters);
89             hasPositiveFilters = true;
90         }
91         if (mNegativeFilters != null && ! mNegativeFilters.isEmpty()) {
92             if (hasPositiveFilters) {
93                 sb.append(":");
94             }
95             sb.append("-");
96             sb.append(mNegativeFilters);
97         }
98         return sb.toString();
99     }
100 
101     /**
102      * @param abi The ABI to run the test on
103      */
setAbi(IAbi abi)104     public void setAbi(IAbi abi) {
105         mAbi = abi;
106         mExeName += mAbi.getBitness();
107     }
108 
109     @Override
run(ITestInvocationListener listener)110     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
111         if (installTest()) {
112             runTest(listener);
113         } else {
114             CLog.e("Failed to install native tests");
115         }
116     }
117 
installTest()118     private boolean installTest() throws DeviceNotAvailableException {
119         if (!createRemoteDir(NATIVE_TESTS_DIRECTORY)) {
120             CLog.e("Could not create directory for native tests: " + NATIVE_TESTS_DIRECTORY);
121             return false;
122         }
123 
124         File nativeExe = new File(mCtsBuild.getTestCasesDir(), mExeName);
125         if (!nativeExe.exists()) {
126             CLog.e("Native test not found: " + nativeExe);
127             return false;
128         }
129 
130         String devicePath = NATIVE_TESTS_DIRECTORY + ANDROID_PATH_SEPARATOR + mExeName;
131         if (!mDevice.pushFile(nativeExe, devicePath)) {
132             CLog.e("Failed to push native test to device");
133             return false;
134         }
135         return true;
136     }
137 
createRemoteDir(String remoteFilePath)138     private boolean createRemoteDir(String remoteFilePath) throws DeviceNotAvailableException {
139         if (mDevice.doesFileExist(remoteFilePath)) {
140             return true;
141         }
142         if (!(mDevice.doesFileExist(NATIVE_TESTS_DIRECTORY_TMP))) {
143             CLog.e("Could not find the /data/local/tmp directory");
144             return false;
145         }
146 
147         mDevice.executeShellCommand(String.format("mkdir %s", remoteFilePath));
148         return mDevice.doesFileExist(remoteFilePath);
149     }
150 
runTest(ITestRunListener listener)151     void runTest(ITestRunListener listener) throws DeviceNotAvailableException {
152         GeeTestResultParser resultParser = new GeeTestResultParser(mPackageName, listener);
153         resultParser.setFakePackagePrefix(mPackageName + ".");
154 
155         String fullPath = NATIVE_TESTS_DIRECTORY + ANDROID_PATH_SEPARATOR + mExeName;
156         String flags = getGTestFilters();
157         CLog.v("Running gtest %s %s on %s", fullPath, flags, mDevice.getSerialNumber());
158         // force file to be executable
159         CLog.v("%s", mDevice.executeShellCommand(String.format("chmod 755 %s", fullPath)));
160 
161         try {
162             mDevice.executeShellCommand(String.format("%s %s", fullPath, flags), resultParser,
163                     mMaxTestTimeMs /* maxTimeToShellOutputResponse */,
164                     0 /* retryAttempts */);
165         } catch (DeviceNotAvailableException e) {
166             resultParser.flush();
167             throw e;
168         } catch (RuntimeException e) {
169             resultParser.flush();
170             throw e;
171         }
172     }
173 
174 
175     @Override
setBuild(IBuildInfo buildInfo)176     public void setBuild(IBuildInfo buildInfo) {
177         mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
178     }
179 
180     @Override
setDevice(ITestDevice device)181     public void setDevice(ITestDevice device) {
182         mDevice = device;
183     }
184 
185     @Override
getDevice()186     public ITestDevice getDevice() {
187         return mDevice;
188     }
189 }
190