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