1 /*
2  * Copyright (C) 2016 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.TestIdentifier;
21 import com.android.tradefed.build.IBuildInfo;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.config.Option.Importance;
24 import com.android.tradefed.device.DeviceNotAvailableException;
25 import com.android.tradefed.device.ITestDevice;
26 import com.android.tradefed.log.LogUtil.CLog;
27 import com.android.tradefed.result.ITestInvocationListener;
28 import com.android.tradefed.testtype.IAbi;
29 import com.android.tradefed.testtype.IBuildReceiver;
30 import com.android.tradefed.testtype.IDeviceTest;
31 import com.android.tradefed.testtype.IRemoteTest;
32 import com.android.tradefed.util.AbiFormatter;
33 import com.android.tradefed.util.ArrayUtil;
34 
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Set;
44 import java.util.concurrent.TimeUnit;
45 
46 /**
47  * {@code Test} for running CTS TestNG tests on the device.
48  */
49 public class TestNGDeviceTest implements IDeviceTest, IRemoteTest, IBuildReceiver {
50 
51     private static final String TMP_DIR = "/data/local/tmp/";
52 
53     @Option(name = "testng-device-runtime",
54             description = "The name of the runtime to use on the device",
55             importance = Importance.ALWAYS)
56     private String mRuntimePath = "dalvikvm|#ABI#|";
57 
58     @Option(name = "testng-device-tmpdir", description = "Device path where to store the test jars."
59             , importance = Importance.IF_UNSET)
60     private String mDeviceTestTmpPath = TMP_DIR;
61 
62 
63     // default to no timeout
64     private long mMaxTimeToOutputResponse = 0;
65 
66     private ITestDevice mDevice;
67     private String mRunName;
68     private Collection<TestIdentifier> mTests;
69     private CtsBuildHelper mCtsBuild = null;
70 
71     private List<String> mJarPaths = new ArrayList<String>();
72 
73     private String mRuntimeArgs;
74 
75     private IAbi mAbi;
76 
77     private static final String TESTNG_JAR = "cts-testng.jar";
78 
79     private Set<String> mTestJars = new HashSet<String>(Arrays.asList(TESTNG_JAR));
80 
81     /**
82      * @param abi The ABI to run the test on
83      */
setAbi(IAbi abi)84     public void setAbi(IAbi abi) {
85         mAbi = abi;
86     }
87 
88     @Override
getDevice()89     public ITestDevice getDevice() {
90         return mDevice;
91     }
92 
93     @Override
setDevice(ITestDevice device)94     public void setDevice(ITestDevice device) {
95         mDevice = device;
96     }
97 
addTestJarFileName(String jarFileName)98     public void addTestJarFileName(String jarFileName) {
99         mTestJars.add(jarFileName);
100     }
101 
setRunName(String runName)102     public void setRunName(String runName) {
103         mRunName = runName;
104     }
105 
setTests(Collection<TestIdentifier> tests)106     public void setTests(Collection<TestIdentifier> tests) {
107         mTests = tests;
108     }
109 
getTests()110     public Collection<TestIdentifier> getTests() {
111         return mTests;
112     }
113 
114     @Override
run(ITestInvocationListener listener)115     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
116         addTestJarFileName(TESTNG_JAR);
117         checkFields();
118         long startTime = System.currentTimeMillis();
119         listener.testRunStarted(mRunName, mTests.size());
120         try {
121             installJars();
122             String jarPath = ArrayUtil.join(":", mJarPaths);
123             for (TestIdentifier testId : mTests) {
124                 SingleJUnitTestResultParser resultParser = new SingleJUnitTestResultParser(
125                         testId, listener);
126                 String cmdLine = String.format("ANDROID_DATA=%s %s -cp %s %s " +
127                         "com.android.cts.testng.SingleTestNGTestRunner %s#%s",
128                         mDeviceTestTmpPath, mRuntimePath, jarPath, getRuntimeArgsNotNull(),
129                         testId.getClassName(), testId.getTestName());
130                 String cmd = AbiFormatter.formatCmdForAbi(cmdLine, mAbi.getBitness());
131                 CLog.d("Running %s", cmd);
132                 listener.testStarted(testId);
133                 mDevice.executeShellCommand(cmd, resultParser, mMaxTimeToOutputResponse,
134                         TimeUnit.MILLISECONDS, 0);
135             }
136         } finally {
137             listener.testRunEnded(System.currentTimeMillis() - startTime,
138                     Collections.<String, String> emptyMap());
139             // Remove jar files from device
140             removeJars();
141         }
142     }
143 
144     /**
145      * Installs the jar files on the device under test.
146      *
147      * @throws DeviceNotAvailableException
148      */
installJars()149     protected void installJars() throws DeviceNotAvailableException {
150         for (String f : mTestJars) {
151             CLog.d("Installing %s on %s", f, getDevice().getSerialNumber());
152             File jarFile;
153             try {
154                 String fullJarPath = String.format("%s%s", mDeviceTestTmpPath, f);
155                 jarFile = mCtsBuild.getTestApp(f);
156                 boolean result = getDevice().pushFile(jarFile, fullJarPath);
157                 if (!result) {
158                     throw new AssertionError(String.format("Failed to push file to %s", fullJarPath));
159                 }
160                 mJarPaths.add(fullJarPath);
161             } catch (FileNotFoundException e) {
162                 throw new AssertionError(String.format("Could not find file %s", f));
163             }
164         }
165     }
166 
167     /**
168      * Cleans up the jar files from the device under test.
169      *
170      * @throws DeviceNotAvailableException
171      */
removeJars()172     protected void removeJars() throws DeviceNotAvailableException {
173         for (String f : mTestJars) {
174             String fullJarPath = String.format("%s%s", mDeviceTestTmpPath, f);
175             CLog.d("Uninstalling %s on %s", fullJarPath, getDevice().getSerialNumber());
176             getDevice().executeShellCommand(String.format("rm %s", fullJarPath));
177         }
178     }
179 
180     @Override
setBuild(IBuildInfo buildInfo)181     public void setBuild(IBuildInfo buildInfo) {
182         mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
183     }
184 
185     /**
186      * Checks that all mandatory member fields has been set.
187      */
checkFields()188     protected void checkFields() {
189         if (mRunName == null) {
190             throw new IllegalArgumentException("run name has not been set");
191         }
192         if (mDevice == null) {
193             throw new IllegalArgumentException("Device has not been set");
194         }
195         if (mTestJars.isEmpty()) {
196             throw new IllegalArgumentException("No test jar has been set");
197         }
198         if (mTests == null) {
199             throw new IllegalArgumentException("tests has not been set");
200         }
201         if (mCtsBuild == null) {
202             throw new IllegalArgumentException("build has not been set");
203         }
204         for (String f : mTestJars) {
205             try {
206 
207                 mCtsBuild.getTestApp(f);
208             } catch (FileNotFoundException e) {
209                 throw new IllegalArgumentException(String.format(
210                         "Could not find jar %s in CTS build %s", f,
211                         mCtsBuild.getRootDir().getAbsolutePath()));
212             }
213         }
214     }
215 
216     /**
217      * Add runtime arguments to run the tests with.
218      *
219      * @param mRunTimeArgs
220      */
addRunTimeArgs(String mRunTimeArgs)221     public void addRunTimeArgs(String mRunTimeArgs) {
222         mRuntimeArgs = mRunTimeArgs;
223     }
224 
getRuntimeArgsNotNull()225     private String getRuntimeArgsNotNull() {
226       if (mRuntimeArgs == null) {
227         return "";
228       }
229       return mRuntimeArgs;
230     }
231 }
232