• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.ddmlib.testrunner.TestIdentifier;
20 import com.android.tradefed.log.LogUtil.CLog;
21 import com.android.tradefed.testtype.IRemoteTest;
22 import com.android.tradefed.testtype.InstrumentationTest;
23 import com.android.tradefed.util.StreamUtil;
24 
25 import java.io.BufferedInputStream;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.security.DigestInputStream;
32 import java.security.MessageDigest;
33 import java.security.NoSuchAlgorithmException;
34 import java.util.Collection;
35 import java.util.LinkedHashSet;
36 
37 /**
38  * Container for CTS test info.
39  * <p/>
40  * Knows how to translate this info into a runnable {@link IRemoteTest}.
41  */
42 class TestPackageDef implements ITestPackageDef {
43 
44     public static final String HOST_SIDE_ONLY_TEST = "hostSideOnly";
45     public static final String NATIVE_TEST = "native";
46     public static final String VM_HOST_TEST = "vmHostTest";
47     public static final String ACCESSIBILITY_TEST =
48         "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
49     public static final String ACCESSIBILITYSERVICE_TEST =
50         "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
51 
52     private static final String SIGNATURE_TEST_METHOD = "testSignature";
53     private static final String SIGNATURE_TEST_CLASS = "android.tests.sigtest.SimpleSignatureTest";
54 
55     private String mUri = null;
56     private String mAppNameSpace = null;
57     private String mName = null;
58     private String mRunner = null;
59     private boolean mIsVMHostTest = false;
60     private String mTestType = null;
61     private String mJarPath = null;
62     private boolean mIsSignatureTest = false;
63     private String mTestPackageName = null;
64     private String mDigest = null;
65 
66     // use a LinkedHashSet for predictable iteration insertion-order, and fast
67     // lookups
68     private Collection<TestIdentifier> mTests = new LinkedHashSet<TestIdentifier>();
69     // also maintain an index of known test classes
70     private Collection<String> mTestClasses = new LinkedHashSet<String>();
71 
72     // dynamic options, not parsed from package xml
73     private String mClassName;
74     private String mMethodName;
75     private TestFilter mExcludedTestFilter = new TestFilter();
76     private String mTargetBinaryName;
77     private String mTargetNameSpace;
78 
setUri(String uri)79     void setUri(String uri) {
80         mUri = uri;
81     }
82 
83     /**
84      * {@inheritDoc}
85      */
86     @Override
getUri()87     public String getUri() {
88         return mUri;
89     }
90 
setAppNameSpace(String appNameSpace)91     void setAppNameSpace(String appNameSpace) {
92         mAppNameSpace = appNameSpace;
93     }
94 
getAppNameSpace()95     String getAppNameSpace() {
96         return mAppNameSpace;
97     }
98 
setName(String name)99     void setName(String name) {
100         mName = name;
101     }
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
getName()107     public String getName() {
108         return mName;
109     }
110 
setRunner(String runnerName)111     void setRunner(String runnerName) {
112         mRunner = runnerName;
113     }
114 
getRunner()115     String getRunner() {
116         return mRunner;
117     }
118 
setTestType(String testType)119     void setTestType(String testType) {
120         mTestType = testType;
121     }
122 
getTestType()123     String getTestType() {
124         return mTestType;
125     }
126 
setJarPath(String jarPath)127     void setJarPath(String jarPath) {
128         mJarPath = jarPath;
129     }
130 
getJarPath()131     String getJarPath() {
132         return mJarPath;
133     }
134 
setIsSignatureCheck(boolean isSignatureCheckTest)135     void setIsSignatureCheck(boolean isSignatureCheckTest) {
136         mIsSignatureTest = isSignatureCheckTest;
137     }
138 
isSignatureCheck()139     boolean isSignatureCheck() {
140         return mIsSignatureTest;
141     }
142 
setTestPackageName(String testPackageName)143     void setTestPackageName(String testPackageName) {
144         mTestPackageName = testPackageName;
145     }
146 
setTargetBinaryName(String targetBinaryName)147     void setTargetBinaryName(String targetBinaryName) {
148         mTargetBinaryName = targetBinaryName;
149     }
150 
setTargetNameSpace(String targetNameSpace)151     void setTargetNameSpace(String targetNameSpace) {
152         mTargetNameSpace = targetNameSpace;
153     }
154 
155     @Override
getTargetApkName()156     public String getTargetApkName() {
157        if (mTargetBinaryName != null && !mTargetBinaryName.isEmpty()) {
158            return String.format("%s.apk", mTargetBinaryName);
159        }
160        return null;
161     }
162 
163     @Override
getTargetPackageName()164     public String getTargetPackageName() {
165         if (mTargetNameSpace != null && mTargetNameSpace.isEmpty()) {
166             return null;
167         }
168         return mTargetNameSpace;
169     }
170 
171     /**
172      * {@inheritDoc}
173      */
174     @Override
setExcludedTestFilter(TestFilter excludeFilter)175     public void setExcludedTestFilter(TestFilter excludeFilter) {
176         mExcludedTestFilter = excludeFilter;
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
setClassName(String className, String methodName)183     public void setClassName(String className, String methodName) {
184         mClassName = className;
185         mMethodName = methodName;
186     }
187 
188     /**
189      * {@inheritDoc}
190      */
191     @Override
createTest(File testCaseDir)192     public IRemoteTest createTest(File testCaseDir) {
193         mExcludedTestFilter.setTestInclusion(mClassName, mMethodName);
194         mTests = filterTests();
195 
196         if (HOST_SIDE_ONLY_TEST.equals(mTestType)) {
197             CLog.d("Creating host test for %s", mName);
198             JarHostTest hostTest = new JarHostTest();
199             hostTest.setRunName(getUri());
200             hostTest.setJarFileName(mJarPath);
201             hostTest.setTests(mTests);
202             mDigest = generateDigest(testCaseDir, mJarPath);
203             return hostTest;
204         } else if (VM_HOST_TEST.equals(mTestType)) {
205             CLog.d("Creating vm host test for %s", mName);
206             VMHostTest vmHostTest = new VMHostTest();
207             vmHostTest.setRunName(getUri());
208             vmHostTest.setJarFileName(mJarPath);
209             vmHostTest.setTests(mTests);
210             mDigest = generateDigest(testCaseDir, mJarPath);
211             return vmHostTest;
212         } else if (NATIVE_TEST.equals(mTestType)) {
213             return new GeeTest(mUri, mName);
214         } else if (ACCESSIBILITY_TEST.equals(mTestType)) {
215             AccessibilityTestRunner test = new AccessibilityTestRunner();
216             return setInstrumentationTest(test, testCaseDir);
217         } else if (ACCESSIBILITYSERVICE_TEST.equals(mTestType)) {
218             AccessibilityServiceTestRunner test = new AccessibilityServiceTestRunner();
219             return setInstrumentationTest(test, testCaseDir);
220         } else if (mIsSignatureTest) {
221             // TODO: hardcode the runner/class/method for now, since current package xml points to
222             // specialized instrumentation. Eventually this special case for signatureTest can be
223             // removed, and it can be treated just like a normal InstrumentationTest
224             CLog.d("Creating signature test %s", mName);
225             InstrumentationApkTest instrTest = new InstrumentationApkTest();
226             instrTest.setPackageName(mAppNameSpace);
227             instrTest.setRunnerName("android.test.InstrumentationTestRunner");
228             instrTest.setClassName(SIGNATURE_TEST_CLASS);
229             instrTest.setMethodName(SIGNATURE_TEST_METHOD);
230             // set expected tests to the single signature test
231             TestIdentifier t = new TestIdentifier(SIGNATURE_TEST_CLASS, SIGNATURE_TEST_METHOD);
232             mTests.clear();
233             mTests.add(t);
234             // mName means 'apk file name' for instrumentation tests
235             instrTest.addInstallApk(String.format("%s.apk", mName), mAppNameSpace);
236             mDigest = generateDigest(testCaseDir, String.format("%s.apk", mName));
237             return instrTest;
238         } else {
239             CLog.d("Creating instrumentation test for %s", mName);
240             InstrumentationApkTest instrTest = new InstrumentationApkTest();
241             return setInstrumentationTest(instrTest, testCaseDir);
242         }
243     }
244 
245     /**
246      * Populates given {@link InstrumentationApkTest} with data from the package xml.
247      *
248      * @param testCaseDir
249      * @param instrTest
250      * @return the populated {@link InstrumentationTest} or <code>null</code>
251      */
setInstrumentationTest(InstrumentationApkTest instrTest, File testCaseDir)252     private InstrumentationTest setInstrumentationTest(InstrumentationApkTest instrTest,
253             File testCaseDir) {
254         instrTest.setRunName(getUri());
255         instrTest.setPackageName(mAppNameSpace);
256         instrTest.setRunnerName(mRunner);
257         instrTest.setTestPackageName(mTestPackageName);
258         instrTest.setClassName(mClassName);
259         instrTest.setMethodName(mMethodName);
260         instrTest.setTestsToRun(mTests,
261                 !mExcludedTestFilter.hasExclusion()
262                 /* only force batch mode if no tests are excluded */);
263         // mName means 'apk file name' for instrumentation tests
264         instrTest.addInstallApk(String.format("%s.apk", mName), mAppNameSpace);
265         mDigest = generateDigest(testCaseDir, String.format("%s.apk", mName));
266         if (mTests.size() > 1000) {
267             // TODO: hack, large test suites can take longer to collect tests, increase timeout
268             instrTest.setCollectsTestsShellTimeout(10 * 60 * 1000);
269         }
270         return instrTest;
271     }
272 
273     /**
274      * Filter the tests to run based on list of excluded tests, class and method name.
275      *
276      * @return the filtered collection of tests
277      */
filterTests()278     private Collection<TestIdentifier> filterTests() {
279         mExcludedTestFilter.setTestInclusion(mClassName, mMethodName);
280         return mExcludedTestFilter.filter(mTests);
281     }
282 
283     /**
284      * {@inheritDoc}
285      */
286     @Override
isKnownTest(TestIdentifier testDef)287     public boolean isKnownTest(TestIdentifier testDef) {
288         return mTests.contains(testDef);
289     }
290 
291     /**
292      * {@inheritDoc}
293      */
294     @Override
isKnownTestClass(String className)295     public boolean isKnownTestClass(String className) {
296         return mTestClasses.contains(className);
297     }
298 
299     /**
300      * Add a {@link TestIdentifier} to the list of tests in this package.
301      *
302      * @param testDef
303      */
addTest(TestIdentifier testDef)304     void addTest(TestIdentifier testDef) {
305         mTests.add(testDef);
306         mTestClasses.add(testDef.getClassName());
307     }
308 
309     /**
310      * Get the collection of tests in this test package.
311      */
312     @Override
getTests()313     public Collection<TestIdentifier> getTests() {
314         return mTests;
315     }
316 
317     /**
318      * {@inheritDoc}
319      */
320     @Override
getDigest()321     public String getDigest() {
322         return mDigest;
323     }
324 
325     /**
326      * Generate a sha1sum digest for a file.
327      * <p/>
328      * Exposed for unit testing.
329      *
330      * @param fileDir the directory of the file
331      * @param fileName the name of the file
332      * @return a hex {@link String} of the digest
333      */
generateDigest(File fileDir, String fileName)334     String generateDigest(File fileDir, String fileName) {
335         final String algorithm = "SHA-1";
336         InputStream fileStream = null;
337         DigestInputStream d = null;
338         try {
339             fileStream = getFileStream(fileDir, fileName);
340             MessageDigest md = MessageDigest.getInstance(algorithm);
341             d = new DigestInputStream(fileStream, md);
342             byte[] buffer = new byte[8196];
343             while (d.read(buffer) != -1) {
344             }
345             return toHexString(md.digest());
346         } catch (NoSuchAlgorithmException e) {
347             return algorithm + " not found";
348         } catch (IOException e) {
349             CLog.e(e);
350         } finally {
351             StreamUtil.closeStream(d);
352             StreamUtil.closeStream(fileStream);
353         }
354         return "failed to generate digest";
355     }
356 
357     /**
358      * Retrieve an input stream for given file
359      * <p/>
360      * Exposed so unit tests can mock.
361      */
getFileStream(File fileDir, String fileName)362     InputStream getFileStream(File fileDir, String fileName) throws FileNotFoundException {
363         InputStream fileStream;
364         fileStream = new BufferedInputStream(new FileInputStream(new File(fileDir, fileName)));
365         return fileStream;
366     }
367 
368     /**
369      * Convert the given byte array into a lowercase hex string.
370      *
371      * @param arr The array to convert.
372      * @return The hex encoded string.
373      */
toHexString(byte[] arr)374     private String toHexString(byte[] arr) {
375         StringBuffer buf = new StringBuffer(arr.length * 2);
376         for (byte b : arr) {
377             buf.append(String.format("%02x", b & 0xFF));
378         }
379         return buf.toString();
380     }
381 }
382