• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 import com.android.cts.util.AbiUtils;
17 
18 import org.junit.runner.RunWith;
19 import org.w3c.dom.Document;
20 import org.w3c.dom.Element;
21 import org.w3c.dom.Node;
22 import org.w3c.dom.NodeList;
23 
24 import vogar.Expectation;
25 import vogar.ExpectationStore;
26 
27 import java.io.BufferedReader;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.FileReader;
31 import java.io.IOException;
32 import java.lang.annotation.Annotation;
33 import java.lang.reflect.Method;
34 import java.lang.reflect.Modifier;
35 import java.util.ArrayList;
36 import java.util.Enumeration;
37 import java.util.HashSet;
38 import java.util.Iterator;
39 import java.util.LinkedHashMap;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.jar.JarEntry;
43 import java.util.jar.JarFile;
44 
45 import javax.xml.parsers.DocumentBuilderFactory;
46 import javax.xml.parsers.ParserConfigurationException;
47 
48 import junit.framework.TestCase;
49 
50 public class CollectAllTests extends DescriptionGenerator {
51 
52     private static final String ATTRIBUTE_RUNNER = "runner";
53     private static final String ATTRIBUTE_PACKAGE = "appPackageName";
54     private static final String ATTRIBUTE_NS = "appNameSpace";
55     private static final String ATTRIBUTE_TARGET = "targetNameSpace";
56     private static final String ATTRIBUTE_TARGET_BINARY = "targetBinaryName";
57     private static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly";
58     private static final String ATTRIBUTE_VM_HOST_TEST = "vmHostTest";
59     private static final String ATTRIBUTE_JAR_PATH = "jarPath";
60     private static final String ATTRIBUTE_JAVA_PACKAGE_FILTER = "javaPackageFilter";
61 
62     private static final String JAR_PATH = "LOCAL_JAR_PATH :=";
63     private static final String TEST_TYPE = "LOCAL_TEST_TYPE :";
64 
main(String[] args)65     public static void main(String[] args) {
66         if (args.length < 5 || args.length > 7) {
67             System.err.println("usage: CollectAllTests <output-file> <manifest-file> <jar-file> "
68                                + "<java-package> <architecture> [expectation-dir [makefile-file]]");
69             if (args.length != 0) {
70                 System.err.println("received:");
71                 for (String arg : args) {
72                     System.err.println("  " + arg);
73                 }
74             }
75             System.exit(1);
76         }
77 
78         final String outputPathPrefix = args[0];
79         File manifestFile = new File(args[1]);
80         String jarFileName = args[2];
81         final String javaPackageFilterArg = args[3] != null ? args[3].replaceAll("\\s+", "") : "";
82         final String[] javaPackagePrefixes;
83         // Validate the javaPackageFilter value if non-empty.
84         if (!javaPackageFilterArg.isEmpty()) {
85             javaPackagePrefixes = javaPackageFilterArg.split(":");
86             for (int i = 0; i < javaPackagePrefixes.length; ++i) {
87                 final String javaPackageFilter = javaPackagePrefixes[i];
88                 if (!isValidJavaPackage(javaPackageFilter)) {
89                     System.err.println("Invalid " + ATTRIBUTE_JAVA_PACKAGE_FILTER + ": " +
90                            javaPackageFilter);
91                     System.exit(1);
92                     return;
93                 } else {
94                     javaPackagePrefixes[i] = javaPackageFilter.trim() + ".";
95                 }
96             }
97         } else {
98             javaPackagePrefixes = new String[0];
99         }
100 
101         String architecture = args[4];
102         if (architecture == null || architecture.equals("")) {
103             System.err.println("Invalid architecture");
104             System.exit(1);
105             return;
106         }
107         String libcoreExpectationDir = (args.length > 5) ? args[5] : null;
108         String androidMakeFile = (args.length > 6) ? args[6] : null;
109 
110         final TestType testType = TestType.getTestType(androidMakeFile);
111 
112         Document manifest;
113         try {
114             manifest = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
115                   new FileInputStream(manifestFile));
116         } catch (Exception e) {
117             System.err.println("cannot open manifest " + manifestFile);
118             e.printStackTrace();
119             System.exit(1);
120             return;
121         }
122 
123         Element documentElement = manifest.getDocumentElement();
124         documentElement.getAttribute("package");
125         final String runner = getElementAttribute(documentElement,
126                                                   "instrumentation",
127                                                   "android:name");
128         final String packageName = documentElement.getAttribute("package");
129         final String target = getElementAttribute(documentElement,
130                                                   "instrumentation",
131                                                   "android:targetPackage");
132 
133         String outputXmlFile = outputPathPrefix + ".xml";
134         final String xmlName = new File(outputPathPrefix).getName();
135         XMLGenerator xmlGenerator;
136         try {
137             xmlGenerator = new XMLGenerator(outputXmlFile) {
138                 {
139                     Node testPackageElem = mDoc.getDocumentElement();
140 
141                     setAttribute(testPackageElem, ATTRIBUTE_NAME, xmlName);
142                     setAttribute(testPackageElem, ATTRIBUTE_RUNNER, runner);
143                     setAttribute(testPackageElem, ATTRIBUTE_PACKAGE, packageName);
144                     setAttribute(testPackageElem, ATTRIBUTE_NS, packageName);
145                     setAttribute(testPackageElem, ATTRIBUTE_JAVA_PACKAGE_FILTER, javaPackageFilterArg);
146 
147                     if (testType.type == TestType.HOST_SIDE_ONLY) {
148                         setAttribute(testPackageElem, ATTRIBUTE_HOST_SIDE_ONLY, "true");
149                         setAttribute(testPackageElem, ATTRIBUTE_JAR_PATH, testType.jarPath);
150                     }
151 
152                     if (testType.type == TestType.VM_HOST_TEST) {
153                         setAttribute(testPackageElem, ATTRIBUTE_VM_HOST_TEST, "true");
154                         setAttribute(testPackageElem, ATTRIBUTE_JAR_PATH, testType.jarPath);
155                     }
156 
157                     if (!packageName.equals(target)) {
158                         setAttribute(testPackageElem, ATTRIBUTE_TARGET, target);
159                         setAttribute(testPackageElem, ATTRIBUTE_TARGET_BINARY, target);
160                     }
161                 }
162             };
163         } catch (ParserConfigurationException e) {
164             System.err.println("Can't initialize XML Generator " + outputXmlFile);
165             System.exit(1);
166             return;
167         }
168 
169         ExpectationStore libcoreVogarExpectationStore;
170         ExpectationStore ctsVogarExpectationStore;
171 
172         try {
173             libcoreVogarExpectationStore
174                     = VogarUtils.provideExpectationStore(libcoreExpectationDir);
175             ctsVogarExpectationStore = VogarUtils.provideExpectationStore(CTS_EXPECTATION_DIR);
176         } catch (IOException e) {
177             System.err.println("Can't initialize vogar expectation store from "
178                                + libcoreExpectationDir);
179             e.printStackTrace(System.err);
180             System.exit(1);
181             return;
182         }
183         ExpectationStore[] expectations = new ExpectationStore[] {
184             libcoreVogarExpectationStore, ctsVogarExpectationStore
185         };
186 
187         JarFile jarFile = null;
188         try {
189             jarFile = new JarFile(jarFileName);
190         } catch (Exception e) {
191             System.err.println("cannot open jarfile " + jarFileName);
192             e.printStackTrace();
193             System.exit(1);
194         }
195 
196         Map<String,TestClass> testCases = new LinkedHashMap<String, TestClass>();
197 
198         Enumeration<JarEntry> jarEntries = jarFile.entries();
199         while (jarEntries.hasMoreElements()) {
200             JarEntry jarEntry = jarEntries.nextElement();
201             String name = jarEntry.getName();
202             if (!name.endsWith(".class")) {
203                 continue;
204             }
205             String className
206                     = name.substring(0, name.length() - ".class".length()).replace('/', '.');
207 
208             boolean matchesPrefix = false;
209             if (javaPackagePrefixes.length > 0) {
210                 for (String javaPackagePrefix : javaPackagePrefixes) {
211                     if (className.startsWith(javaPackagePrefix)) {
212                         matchesPrefix = true;
213                     }
214                 }
215             } else {
216                 matchesPrefix = true;
217             }
218 
219             if (!matchesPrefix) {
220                 continue;
221             }
222 
223             try {
224                 Class<?> klass = Class.forName(className,
225                                                false,
226                                                CollectAllTests.class.getClassLoader());
227                 final int modifiers = klass.getModifiers();
228                 if (Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers)) {
229                     continue;
230                 }
231 
232                 final boolean isJunit4Class = isJunit4Class(klass);
233                 if (!isJunit4Class && !isJunit3Test(klass)) {
234                     continue;
235                 }
236 
237                 try {
238                     klass.getConstructor(new Class<?>[] { String.class } );
239                     addToTests(expectations, architecture, testCases, klass);
240                     continue;
241                 } catch (NoSuchMethodException e) {
242                 } catch (SecurityException e) {
243                     System.out.println("Known bug (Working as intended): problem with class "
244                             + className);
245                     e.printStackTrace();
246                 }
247 
248                 try {
249                     klass.getConstructor(new Class<?>[0]);
250                     addToTests(expectations, architecture, testCases, klass);
251                     continue;
252                 } catch (NoSuchMethodException e) {
253                 } catch (SecurityException e) {
254                     System.out.println("Known bug (Working as intended): problem with class "
255                             + className);
256                     e.printStackTrace();
257                 }
258             } catch (ClassNotFoundException e) {
259                 System.out.println("class not found " + className);
260                 e.printStackTrace();
261                 System.exit(1);
262             }
263         }
264 
265         for (Iterator<TestClass> iterator = testCases.values().iterator(); iterator.hasNext();) {
266             TestClass type = iterator.next();
267             xmlGenerator.addTestClass(type);
268         }
269 
270         try {
271             xmlGenerator.dump();
272         } catch (Exception e) {
273             System.err.println("cannot dump xml to " + outputXmlFile);
274             e.printStackTrace();
275             System.exit(1);
276         }
277     }
278 
279     private static class TestType {
280         private static final int HOST_SIDE_ONLY = 1;
281         private static final int DEVICE_SIDE_ONLY = 2;
282         private static final int VM_HOST_TEST = 3;
283 
284         private final int type;
285         private final String jarPath;
286 
TestType(int type, String jarPath)287         private TestType (int type, String jarPath) {
288             this.type = type;
289             this.jarPath = jarPath;
290         }
291 
getTestType(String makeFileName)292         private static TestType getTestType(String makeFileName) {
293             if (makeFileName == null || makeFileName.isEmpty()) {
294                 return new TestType(DEVICE_SIDE_ONLY, null);
295             }
296             int type = TestType.DEVICE_SIDE_ONLY;
297             String jarPath = null;
298             try {
299                 BufferedReader reader = new BufferedReader(new FileReader(makeFileName));
300                 String line;
301 
302                 while ((line = reader.readLine())!=null) {
303                     if (line.startsWith(TEST_TYPE)) {
304                         if (line.indexOf(ATTRIBUTE_VM_HOST_TEST) >= 0) {
305                             type = VM_HOST_TEST;
306                         } else {
307                             type = HOST_SIDE_ONLY;
308                         }
309                     } else if (line.startsWith(JAR_PATH)) {
310                         jarPath = line.substring(JAR_PATH.length(), line.length()).trim();
311                     }
312                 }
313                 reader.close();
314             } catch (IOException e) {
315             }
316             return new TestType(type, jarPath);
317         }
318     }
319 
getElement(Element element, String tagName)320     private static Element getElement(Element element, String tagName) {
321         NodeList elements = element.getElementsByTagName(tagName);
322         if (elements.getLength() > 0) {
323             return (Element) elements.item(0);
324         } else {
325             return null;
326         }
327     }
328 
getElementAttribute(Element element, String elementName, String attributeName)329     private static String getElementAttribute(Element element,
330                                               String elementName,
331                                               String attributeName) {
332         Element e = getElement(element, elementName);
333         if (e != null) {
334             return e.getAttribute(attributeName);
335         } else {
336             return "";
337         }
338     }
339 
getKnownFailure(final Class<?> testClass, final String testName)340     private static String getKnownFailure(final Class<?> testClass,
341             final String testName) {
342         return getAnnotation(testClass, testName, KNOWN_FAILURE);
343     }
344 
isKnownFailure(final Class<?> testClass, final String testName)345     private static boolean isKnownFailure(final Class<?> testClass,
346             final String testName) {
347         return getAnnotation(testClass, testName, KNOWN_FAILURE) != null;
348     }
349 
isSuppressed(final Class<?> testClass, final String testName)350     private static boolean isSuppressed(final Class<?> testClass,
351             final String testName)  {
352         return getAnnotation(testClass, testName, SUPPRESSED_TEST) != null;
353     }
354 
getAnnotation(final Class<?> testClass, final String testName, final String annotationName)355     private static String getAnnotation(final Class<?> testClass,
356             final String testName, final String annotationName) {
357         try {
358             Method testMethod = testClass.getMethod(testName, (Class[])null);
359             Annotation[] annotations = testMethod.getAnnotations();
360             for (Annotation annot : annotations) {
361 
362                 if (annot.annotationType().getName().equals(annotationName)) {
363                     String annotStr = annot.toString();
364                     String knownFailure = null;
365                     if (annotStr.contains("(value=")) {
366                         knownFailure =
367                             annotStr.substring(annotStr.indexOf("=") + 1,
368                                     annotStr.length() - 1);
369 
370                     }
371 
372                     if (knownFailure == null) {
373                         knownFailure = "true";
374                     }
375 
376                     return knownFailure;
377                 }
378 
379             }
380 
381         } catch (NoSuchMethodException e) {
382         }
383 
384         return null;
385     }
386 
addToTests(ExpectationStore[] expectations, String architecture, Map<String,TestClass> testCases, Class<?> testClass)387     private static void addToTests(ExpectationStore[] expectations,
388                                    String architecture,
389                                    Map<String,TestClass> testCases,
390                                    Class<?> testClass) {
391         Set<String> testNames = new HashSet<String>();
392 
393         boolean isJunit3Test = isJunit3Test(testClass);
394 
395         Method[] testMethods = testClass.getMethods();
396         for (Method testMethod : testMethods) {
397             String testName = testMethod.getName();
398             if (testNames.contains(testName)) {
399                 continue;
400             }
401 
402             /* Make sure the method has the right signature. */
403             if (!Modifier.isPublic(testMethod.getModifiers())) {
404                 continue;
405             }
406             if (!testMethod.getReturnType().equals(Void.TYPE)) {
407                 continue;
408             }
409             if (testMethod.getParameterTypes().length != 0) {
410                 continue;
411             }
412 
413             if ((isJunit3Test && !testName.startsWith("test"))
414                     || (!isJunit3Test && !isJunit4TestMethod(testMethod))) {
415                 continue;
416             }
417 
418             testNames.add(testName);
419             addToTests(expectations, architecture, testCases, testClass, testName);
420         }
421     }
422 
addToTests(ExpectationStore[] expectations, String architecture, Map<String,TestClass> testCases, Class<?> test, String testName)423     private static void addToTests(ExpectationStore[] expectations,
424                                    String architecture,
425                                    Map<String,TestClass> testCases,
426                                    Class<?> test,
427                                    String testName) {
428 
429         String testClassName = test.getName();
430         String knownFailure = getKnownFailure(test, testName);
431 
432         if (isKnownFailure(test, testName)) {
433             System.out.println("ignoring known failure: " + test + "#" + testName);
434             return;
435         } else if (isSuppressed(test, testName)) {
436             System.out.println("ignoring suppressed test: " + test + "#" + testName);
437             return;
438         } else if (VogarUtils.isVogarKnownFailure(expectations,
439                                                   testClassName,
440                                                   testName)) {
441             System.out.println("ignoring expectation known failure: " + test
442                                + "#" + testName);
443             return;
444         }
445 
446         Set<String> supportedAbis = VogarUtils.extractSupportedAbis(architecture,
447                                                                     expectations,
448                                                                     testClassName,
449                                                                     testName);
450         int timeoutInMinutes = VogarUtils.timeoutInMinutes(expectations,
451                                                            testClassName,
452                                                            testName);
453         TestClass testClass;
454         if (testCases.containsKey(testClassName)) {
455             testClass = testCases.get(testClassName);
456         } else {
457             testClass = new TestClass(testClassName, new ArrayList<TestMethod>());
458             testCases.put(testClassName, testClass);
459         }
460 
461         testClass.mCases.add(new TestMethod(testName, "", "", supportedAbis,
462               knownFailure, false, false, timeoutInMinutes));
463     }
464 
isJunit3Test(Class<?> klass)465     private static boolean isJunit3Test(Class<?> klass) {
466         return TestCase.class.isAssignableFrom(klass);
467     }
468 
isJunit4Class(Class<?> klass)469     private static boolean isJunit4Class(Class<?> klass) {
470         for (Annotation a : klass.getAnnotations()) {
471             if (RunWith.class.isAssignableFrom(a.annotationType())) {
472                 // @RunWith is currently not supported for CTS tests because tradefed cannot handle
473                 // a single test spawning other tests with different names.
474                 System.out.println("Skipping test class " + klass.getName()
475                         + ": JUnit4 @RunWith is not supported");
476                 return false;
477             }
478         }
479 
480         for (Method m : klass.getMethods()) {
481             if (isJunit4TestMethod(m)) {
482                 return true;
483             }
484         }
485 
486         return false;
487     }
488 
isJunit4TestMethod(Method method)489     private static boolean isJunit4TestMethod(Method method) {
490         for (Annotation a : method.getAnnotations()) {
491             if (org.junit.Test.class.isAssignableFrom(a.annotationType())) {
492                 return true;
493             }
494         }
495 
496         return false;
497     }
498 
499     /**
500      * Determines if a given string is a valid java package name
501      * @param javaPackageName
502      * @return true if it is valid, false otherwise
503      */
isValidJavaPackage(String javaPackageName)504     private static boolean isValidJavaPackage(String javaPackageName) {
505         String[] strSections = javaPackageName.split(".");
506         for (String strSection : strSections) {
507           if (!isValidJavaIdentifier(strSection)) {
508               return false;
509           }
510         }
511         return true;
512     }
513 
514     /**
515      * Determines if a given string is a valid java identifier.
516      * @param javaIdentifier
517      * @return true if it is a valid identifier, false otherwise
518      */
isValidJavaIdentifier(String javaIdentifier)519     private static boolean isValidJavaIdentifier(String javaIdentifier) {
520         if (javaIdentifier.length() == 0 ||
521                 !Character.isJavaIdentifierStart(javaIdentifier.charAt(0))) {
522             return false;
523         }
524         for (int i = 1; i < javaIdentifier.length(); i++) {
525             if (!Character.isJavaIdentifierPart(javaIdentifier.charAt(i))) {
526                 return false;
527             }
528         }
529         return true;
530     }
531 }
532