1 /* 2 * Copyright (C) 2018 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.releaseparser; 18 19 import com.android.cts.releaseparser.ReleaseProto.*; 20 import com.android.tools.smali.dexlib2.AccessFlags; 21 import com.android.tools.smali.dexlib2.DexFileFactory; 22 import com.android.tools.smali.dexlib2.Opcodes; 23 import com.android.tools.smali.dexlib2.iface.Annotation; 24 import com.android.tools.smali.dexlib2.iface.AnnotationElement; 25 import com.android.tools.smali.dexlib2.iface.ClassDef; 26 import com.android.tools.smali.dexlib2.iface.DexFile; 27 import com.android.tools.smali.dexlib2.iface.Method; 28 import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue; 29 import com.android.tradefed.testtype.IRemoteTest; 30 31 import junit.framework.Test; 32 33 import org.junit.runner.RunWith; 34 import org.junit.runners.Suite.SuiteClasses; 35 36 import java.io.File; 37 import java.io.FileWriter; 38 import java.io.IOException; 39 import java.io.PrintWriter; 40 import java.lang.reflect.Modifier; 41 import java.net.URL; 42 import java.net.URLClassLoader; 43 import java.nio.charset.StandardCharsets; 44 import java.nio.file.Paths; 45 import java.security.MessageDigest; 46 import java.security.NoSuchAlgorithmException; 47 import java.util.ArrayList; 48 import java.util.Base64; 49 import java.util.Collection; 50 import java.util.Enumeration; 51 import java.util.List; 52 import java.util.Set; 53 import java.util.jar.JarEntry; 54 import java.util.jar.JarFile; 55 56 class TestSuiteParser { 57 // JUNIT3 Test suffix 58 private static final String TEST_TAG = "Test;"; 59 // Some may ends with Tests e.g. cts/tests/tests/accounts/src/android/accounts/cts/AbstractAuthenticatorTests.java 60 private static final String TESTS_TAG = "Tests;"; 61 private static final String TEST_PREFIX_TAG = "test"; 62 private static final String DEPRECATED_ANNOTATION_TAG = "Ljava/lang/Deprecated;"; 63 private static final String RUN_WITH_ANNOTATION_TAG = "Lorg/junit/runner/RunWith;"; 64 private static final String TEST_ANNOTATION_TAG = "Lorg/junit/Test;"; 65 private static final String SUPPRESS_ANNOTATION_TAG = "/Suppress;"; 66 private static final String ANDROID_JUNIT4_TEST_TAG = 67 "Landroid/support/test/runner/AndroidJUnit4;"; 68 private static final String PARAMETERIZED_TEST_TAG = "Lorg/junit/runners/Parameterized;"; 69 70 // configuration option 71 private static final String NOT_SHARDABLE_TAG = "not-shardable"; 72 // test class option 73 private static final String RUNTIME_HIT_TAG = "runtime-hint"; 74 // com.android.tradefed.testtype.AndroidJUnitTest option 75 private static final String PACKAGE_TAG = "package"; 76 // com.android.compatibility.common.tradefed.testtype.JarHostTest option 77 private static final String JAR_TAG = "jar"; 78 // com.android.tradefed.testtype.GTest option 79 private static final String NATIVE_TEST_DEVICE_PATH_TAG = "native-test-device-path"; 80 private static final String MODULE_TAG = "module-name"; 81 private static final String TESTCASES_FOLDER_FORMAT = "testcases/%s"; 82 83 private static final String SUITE_API_INSTALLER_TAG = 84 "com.android.tradefed.targetprep.suite.SuiteApkInstaller"; 85 private static final String HOST_TEST_CLASS_TAG = 86 "com.android.compatibility.common.tradefed.testtype.JarHostTest"; 87 // com.android.tradefed.targetprep.suite.SuiteApkInstaller option 88 private static final String TEST_FILE_NAME_TAG = "test-file-name"; 89 // com.android.compatibility.common.tradefed.targetprep.FilePusher option 90 private static final String PUSH_TAG = "push"; 91 92 // test class 93 private static final String ANDROID_JUNIT_TEST_TAG = 94 "com.android.tradefed.testtype.AndroidJUnitTest"; 95 private static final String DEQP_TEST_TAG = "com.drawelements.deqp.runner.DeqpTestRunner"; 96 private static final String GTEST_TAG = "com.android.tradefed.testtype.GTest"; 97 private static final String LIBCORE_TEST_TAG = "com.android.compatibility.testtype.LibcoreTest"; 98 private static final String DALVIK_TEST_TAG = "com.android.compatibility.testtype.DalvikTest"; 99 100 // Target File Extensions 101 private static final String CONFIG_EXT_TAG = ".config"; 102 private static final String CONFIG_REGEX = ".config$"; 103 private static final String JAR_EXT_TAG = ".jar"; 104 private static final String APK_EXT_TAG = ".apk"; 105 private static final String SO_EXT_TAG = ".so"; 106 107 // [module].[class]#[method] 108 public static final String TESTCASE_NAME_FORMAT = "%s.%s#%s"; 109 110 private final String mFolderPath; 111 private ReleaseContent mRelContent; 112 private TestSuite.Builder mTSBuilder; 113 TestSuiteParser(ReleaseContent relContent, String folder)114 TestSuiteParser(ReleaseContent relContent, String folder) { 115 mFolderPath = folder; 116 mRelContent = relContent; 117 } 118 getTestSuite()119 public TestSuite getTestSuite() { 120 if (mTSBuilder == null) { 121 mTSBuilder = praseTestSuite(); 122 } 123 return mTSBuilder.build(); 124 } 125 praseTestSuite()126 private TestSuite.Builder praseTestSuite() { 127 TestSuite.Builder tsBuilder = TestSuite.newBuilder(); 128 129 tsBuilder.setName(mRelContent.getName()); 130 tsBuilder.setVersion(mRelContent.getVersion()); 131 tsBuilder.setBuildNumber(mRelContent.getBuildNumber()); 132 133 // Iterates all file 134 for (Entry entry : getFileEntriesList(mRelContent)) { 135 // Only parses test module config files 136 if (Entry.EntryType.TEST_MODULE_CONFIG == entry.getType()) { 137 TestModuleConfig config = entry.getTestModuleConfig(); 138 TestSuite.Module.Builder moduleBuilder = praseModule(config); 139 moduleBuilder.setConfigFile(entry.getRelativePath()); 140 tsBuilder.addModules(moduleBuilder); 141 } 142 } 143 return tsBuilder; 144 } 145 praseModule(TestModuleConfig config)146 private TestSuite.Module.Builder praseModule(TestModuleConfig config) { 147 TestSuite.Module.Builder moduleBuilder = TestSuite.Module.newBuilder(); 148 // parse test package and class 149 List<TestModuleConfig.TestClass> testClassesList = config.getTestClassesList(); 150 moduleBuilder.setName(config.getModuleName()); 151 for (TestModuleConfig.TestClass tClass : testClassesList) { 152 String testClass = tClass.getTestClass(); 153 moduleBuilder.setTestClass(testClass); 154 switch (testClass) { 155 case ANDROID_JUNIT_TEST_TAG: 156 moduleBuilder.setTestType(TestSuite.TestType.ANDROIDJUNIT); 157 parseAndroidJUnitTest(moduleBuilder, config, tClass.getTestClass()); 158 break; 159 case HOST_TEST_CLASS_TAG: 160 moduleBuilder.setTestType(TestSuite.TestType.JAVAHOST); 161 parseJavaHostTest(moduleBuilder, config, tClass.getTestClass()); 162 break; 163 default: 164 //ToDo 165 moduleBuilder.setTestType(TestSuite.TestType.UNKNOWN); 166 ApiPackage.Builder pkgBuilder = ApiPackage.newBuilder(); 167 moduleBuilder.addPackages(pkgBuilder); 168 System.err.printf( 169 "ToDo Test Type: %s %s\n", tClass.getTestClass(), tClass.getPackage()); 170 } 171 } 172 return moduleBuilder; 173 } 174 parseAndroidJUnitTest( TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass)175 private void parseAndroidJUnitTest( 176 TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass) { 177 // getting apk list from Test Module Configuration 178 List<TestModuleConfig.TargetPreparer> tPrepList = config.getTargetPreparersList(); 179 for (TestModuleConfig.TargetPreparer tPrep : tPrepList) { 180 for (Option opt : tPrep.getOptionsList()) { 181 if (TEST_FILE_NAME_TAG.equalsIgnoreCase(opt.getName())) { 182 ApiPackage.Builder pkgBuilder = ApiPackage.newBuilder(); 183 String testFileName = opt.getValue(); 184 Entry tEntry = getFileEntry(testFileName); 185 pkgBuilder.setName(testFileName); 186 pkgBuilder.setPackageFile(tEntry.getRelativePath()); 187 pkgBuilder.setContentId(tEntry.getContentId()); 188 parseApkTestCase(pkgBuilder, config); 189 moduleBuilder.addPackages(pkgBuilder); 190 } 191 } 192 } 193 } 194 getFileEntry(String name)195 private Entry getFileEntry(String name) { 196 Entry fEntry = null; 197 for (Entry et : getFileEntriesList(mRelContent)) { 198 if (name.equals(et.getName())) { 199 fEntry = et; 200 break; 201 } 202 } 203 return fEntry; 204 } 205 // Parses test case list from an APK parseApkTestCase(ApiPackage.Builder pkgBuilder, TestModuleConfig config)206 private void parseApkTestCase(ApiPackage.Builder pkgBuilder, TestModuleConfig config) { 207 DexFile dexFile = null; 208 String apkPath = Paths.get(mFolderPath, pkgBuilder.getPackageFile()).toString(); 209 String moduleName = config.getModuleName(); 210 211 // Loads a Dex file 212 try { 213 dexFile = DexFileFactory.loadDexFile(apkPath, Opcodes.getDefault()); 214 215 // Iterates through all clesses in the Dex file 216 for (ClassDef classDef : dexFile.getClasses()) { 217 // adjust the format Lclass/y; 218 String className = classDef.getType().replace('/', '.'); 219 // remove L...; 220 if (className.length() > 2) { 221 className = className.substring(1, className.length() - 1); 222 } 223 224 // Parses test classes 225 TestClassType cType = chkTestClassType(classDef); 226 ApiClass.Builder tClassBuilder = ApiClass.newBuilder(); 227 switch (cType) { 228 case JUNIT3: 229 tClassBuilder.setTestClassType(cType); 230 tClassBuilder.setName(className); 231 // Checks all test method 232 for (Method method : classDef.getMethods()) { 233 // Only care about Public 234 if ((method.getAccessFlags() & AccessFlags.PUBLIC.getValue()) != 0) { 235 String mName = method.getName(); 236 // Warn current test result accounting does not work well with Supress 237 if (hasAnnotationSuffix( 238 method.getAnnotations(), SUPPRESS_ANNOTATION_TAG)) { 239 System.err.printf("%s#%s with Suppress:\n", className, mName); 240 } else if (mName.startsWith(TEST_PREFIX_TAG)) { 241 // Junit3 style test case name starts with test 242 tClassBuilder.addMethods( 243 newTestBuilder( 244 moduleName, className, method.getName())); 245 } else if (hasAnnotationSuffix( 246 method.getAnnotations(), TEST_ANNOTATION_TAG)) { 247 tClassBuilder.addMethods( 248 newTestBuilder( 249 moduleName, className, method.getName())); 250 System.err.printf( 251 "%s#%s JUNIT3 mixes with %s annotation:\n", 252 className, mName, TEST_ANNOTATION_TAG); 253 } 254 } 255 } 256 pkgBuilder.addClasses(tClassBuilder); 257 break; 258 case PARAMETERIZED: 259 // ToDo need to find a way to count Parameterized tests 260 System.err.printf("To count Parameterized tests: %s\n", className); 261 tClassBuilder.setTestClassType(cType); 262 tClassBuilder.setName(className); 263 for (Method method : classDef.getMethods()) { 264 // Junit4 style test case annotated with @Test 265 if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) { 266 tClassBuilder.addMethods( 267 newTestBuilder(moduleName, className, method.getName())); 268 } 269 } 270 pkgBuilder.addClasses(tClassBuilder); 271 break; 272 case JUNIT4: 273 tClassBuilder.setTestClassType(cType); 274 tClassBuilder.setName(className); 275 for (Method method : classDef.getMethods()) { 276 // Junit4 style test case annotated with @Test 277 if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) { 278 tClassBuilder.addMethods( 279 newTestBuilder(moduleName, className, method.getName())); 280 } 281 } 282 pkgBuilder.addClasses(tClassBuilder); 283 break; 284 default: 285 // Not a known test class 286 } 287 } 288 } catch (IOException | DexFileFactory.DexFileNotFoundException ex) { 289 System.err.println("Unable to load dex file: " + apkPath); 290 // ex.printStackTrace(); 291 } 292 } 293 newTestBuilder(String moduleName, String className, String testName)294 private ApiMethod.Builder newTestBuilder(String moduleName, String className, String testName) { 295 ApiMethod.Builder testBuilder = ApiMethod.newBuilder(); 296 testBuilder.setName(testName); 297 // Check if it's an known failure 298 String nfFilter = getKnownFailureFilter(moduleName, className, testName); 299 if (null != nfFilter) { 300 testBuilder.setKnownFailureFilter(nfFilter); 301 } 302 return testBuilder; 303 } 304 parseJavaHostTest( TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass)305 private void parseJavaHostTest( 306 TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass) { 307 ApiPackage.Builder pkgBuilder = ApiPackage.newBuilder(); 308 //Assuming there is only one test Jar 309 String testFileName = config.getTestJars(0); 310 Entry tEntry = getFileEntry(testFileName); 311 String jarPath = tEntry.getRelativePath(); 312 313 pkgBuilder.setName(testFileName); 314 pkgBuilder.setPackageFile(jarPath); 315 pkgBuilder.setContentId(tEntry.getContentId()); 316 Collection<Class<?>> classes = 317 getJarTestClasses( 318 Paths.get(mFolderPath, jarPath).toFile(), 319 // Includes [x]-tradefed.jar for classes such as CompatibilityHostTestBase 320 Paths.get(mFolderPath, mRelContent.getTestSuiteTradefed()).toFile()); 321 322 for (Class<?> c : classes) { 323 ApiClass.Builder tClassBuilder = ApiClass.newBuilder(); 324 tClassBuilder.setTestClassType(TestClassType.JAVAHOST); 325 tClassBuilder.setName(c.getName()); 326 327 for (java.lang.reflect.Method m : c.getMethods()) { 328 int mdf = m.getModifiers(); 329 if (Modifier.isPublic(mdf) || Modifier.isProtected(mdf)) { 330 if (m.getName().startsWith(TEST_PREFIX_TAG)) { 331 ApiMethod.Builder methodBuilder = ApiMethod.newBuilder(); 332 methodBuilder.setName(m.getName()); 333 // Check if it's an known failure 334 String nfFilter = 335 getKnownFailureFilter( 336 config.getModuleName(), c.getName(), m.getName()); 337 if (null != nfFilter) { 338 methodBuilder.setKnownFailureFilter(nfFilter); 339 } 340 tClassBuilder.addMethods(methodBuilder); 341 } 342 } 343 } 344 pkgBuilder.addClasses(tClassBuilder); 345 } 346 moduleBuilder.addPackages(pkgBuilder); 347 } 348 hasAnnotation(Set<? extends Annotation> annotations, String tag)349 private static boolean hasAnnotation(Set<? extends Annotation> annotations, String tag) { 350 for (Annotation annotation : annotations) { 351 if (annotation.getType().equals(tag)) { 352 return true; 353 } 354 } 355 return false; 356 } 357 hasAnnotationSuffix(Set<? extends Annotation> annotations, String tag)358 private static boolean hasAnnotationSuffix(Set<? extends Annotation> annotations, String tag) { 359 for (Annotation annotation : annotations) { 360 if (annotation.getType().endsWith(tag)) { 361 return true; 362 } 363 } 364 return false; 365 } 366 chkTestClassType(ClassDef classDef)367 private static TestClassType chkTestClassType(ClassDef classDef) { 368 // Only care about Public Class 369 if ((classDef.getAccessFlags() & AccessFlags.PUBLIC.getValue()) == 0) { 370 return TestClassType.UNKNOWN; 371 } 372 373 for (Annotation annotation : classDef.getAnnotations()) { 374 if (annotation.getType().equals(DEPRECATED_ANNOTATION_TAG)) { 375 return TestClassType.UNKNOWN; 376 } 377 if (annotation.getType().equals(RUN_WITH_ANNOTATION_TAG)) { 378 for (AnnotationElement annotationEle : annotation.getElements()) { 379 if ("value".equals(annotationEle.getName())) { 380 String aValue = ((TypeEncodedValue) annotationEle.getValue()).getValue(); 381 if (ANDROID_JUNIT4_TEST_TAG.equals(aValue)) { 382 return TestClassType.JUNIT4; 383 } else if (PARAMETERIZED_TEST_TAG.equals(aValue)) { 384 return TestClassType.PARAMETERIZED; 385 } 386 } 387 } 388 System.err.printf("Unknown test class type: %s\n", classDef.getType()); 389 return TestClassType.JUNIT4; 390 } 391 } 392 393 if (classDef.getType().endsWith(TEST_TAG) || classDef.getType().endsWith(TESTS_TAG)) { 394 return TestClassType.JUNIT3; 395 } else { 396 return TestClassType.UNKNOWN; 397 } 398 } 399 isTargetClass(List<String> pkgList, String className)400 private static boolean isTargetClass(List<String> pkgList, String className) { 401 boolean found = false; 402 for (String pkg : pkgList) { 403 if (className.startsWith(pkg)) { 404 found = true; 405 break; 406 } 407 } 408 return found; 409 } 410 getJarTestClasses(File jarTestFile, File tfFile)411 private static Collection<Class<?>> getJarTestClasses(File jarTestFile, File tfFile) 412 throws IllegalArgumentException { 413 List<Class<?>> classes = new ArrayList<>(); 414 415 try (JarFile jarFile = new JarFile(jarTestFile)) { 416 Enumeration<JarEntry> e = jarFile.entries(); 417 418 URL[] urls = { 419 new URL(String.format("jar:file:%s!/", jarTestFile.getAbsolutePath())), 420 new URL(String.format("jar:file:%s!/", tfFile.getAbsolutePath())) 421 }; 422 URLClassLoader cl = 423 URLClassLoader.newInstance(urls, JarTestFinder.class.getClassLoader()); 424 425 while (e.hasMoreElements()) { 426 JarEntry je = e.nextElement(); 427 if (je.isDirectory() 428 || !je.getName().endsWith(".class") 429 || je.getName().contains("$") 430 || je.getName().contains("junit/")) { 431 continue; 432 } 433 String className = getClassName(je.getName()); 434 435 /*if (!className.endsWith("Test")) { 436 continue; 437 }*/ 438 try { 439 Class<?> cls = cl.loadClass(className); 440 441 if (IRemoteTest.class.isAssignableFrom(cls) 442 || Test.class.isAssignableFrom(cls)) { 443 classes.add(cls); 444 } else if (!Modifier.isAbstract(cls.getModifiers()) 445 && hasJUnit4Annotation(cls)) { 446 classes.add(cls); 447 } 448 } catch (ClassNotFoundException | Error x) { 449 System.err.println( 450 String.format( 451 "Cannot find test class %s from %s", 452 className, jarTestFile.getName())); 453 x.printStackTrace(); 454 } 455 } 456 } catch (IOException e) { 457 e.printStackTrace(); 458 } 459 return classes; 460 } 461 462 /** Helper to determine if we are dealing with a Test class with Junit4 annotations. */ hasJUnit4Annotation(Class<?> classObj)463 protected static boolean hasJUnit4Annotation(Class<?> classObj) { 464 if (classObj.isAnnotationPresent(SuiteClasses.class)) { 465 return true; 466 } 467 if (classObj.isAnnotationPresent(RunWith.class)) { 468 return true; 469 } 470 /*for (Method m : classObj.getMethods()) { 471 if (m.isAnnotationPresent(org.junit.Test.class)) { 472 return true; 473 } 474 }*/ 475 return false; 476 } 477 getClassName(String name)478 private static String getClassName(String name) { 479 // -6 because of .class 480 return name.substring(0, name.length() - 6).replace('/', '.'); 481 } 482 getKnownFailureFilter(String tModule, String tClass, String tMethod)483 private String getKnownFailureFilter(String tModule, String tClass, String tMethod) { 484 List<String> knownFailures = mRelContent.getKnownFailuresList(); 485 String tsName = String.format(TESTCASE_NAME_FORMAT, tModule, tClass, tMethod); 486 for (String kf : knownFailures) { 487 if (tsName.startsWith(kf)) { 488 return kf; 489 } 490 } 491 return null; 492 } 493 494 // Iterates though all test suite content and prints them. writeCsvFile(String relNameVer, String csvFile)495 public void writeCsvFile(String relNameVer, String csvFile) { 496 TestSuite ts = getTestSuite(); 497 try { 498 FileWriter fWriter = new FileWriter(csvFile); 499 PrintWriter pWriter = new PrintWriter(fWriter); 500 //Header 501 pWriter.println( 502 "release,module,test_class,test,test_package,test_type,known_failure_filter,package_content_id"); 503 for (TestSuite.Module module : ts.getModulesList()) { 504 for (ApiPackage pkg : module.getPackagesList()) { 505 for (ApiClass cls : pkg.getClassesList()) { 506 for (ApiMethod mtd : cls.getMethodsList()) { 507 pWriter.printf( 508 "%s,%s,%s,%s,%s,%s,%s,%s\n", 509 relNameVer, 510 module.getName(), 511 cls.getName(), 512 mtd.getName(), 513 pkg.getPackageFile(), 514 cls.getTestClassType(), 515 mtd.getKnownFailureFilter(), 516 getTestTargetContentId(pkg.getPackageFile())); 517 } 518 } 519 } 520 } 521 pWriter.flush(); 522 pWriter.close(); 523 } catch (IOException e) { 524 System.err.println("IOException:" + e.getMessage()); 525 } 526 } 527 528 // Iterates though all test module and prints them. writeModuleCsvFile(String relNameVer, String csvFile)529 public void writeModuleCsvFile(String relNameVer, String csvFile) { 530 TestSuite ts = getTestSuite(); 531 try { 532 FileWriter fWriter = new FileWriter(csvFile); 533 PrintWriter pWriter = new PrintWriter(fWriter); 534 535 //Header 536 pWriter.print( 537 "release,module,test_no,known_failure_no,test_type,test_class,component,description,test_config_file,test_file_names,test_jars,module_content_id\n"); 538 539 for (TestSuite.Module module : ts.getModulesList()) { 540 int classCnt = 0; 541 int methodCnt = 0; 542 int kfCnt = 0; 543 for (ApiPackage pkg : module.getPackagesList()) { 544 for (ApiClass cls : pkg.getClassesList()) { 545 for (ApiMethod mtd : cls.getMethodsList()) { 546 // Filter out known failures 547 if (mtd.getKnownFailureFilter().isEmpty()) { 548 methodCnt++; 549 } else { 550 kfCnt++; 551 } 552 } 553 classCnt++; 554 } 555 } 556 String config = module.getConfigFile(); 557 Entry entry = mRelContent.getEntries().get(config); 558 TestModuleConfig tmConfig = entry.getTestModuleConfig(); 559 pWriter.printf( 560 "%s,%s,%d,%d,%s,%s,%s,%s,%s,%s,%s,%s\n", 561 relNameVer, 562 module.getName(), 563 methodCnt, 564 kfCnt, 565 module.getTestType(), 566 module.getTestClass(), 567 tmConfig.getComponent(), 568 tmConfig.getDescription(), 569 config, 570 String.join(" ", tmConfig.getTestFileNamesList()), 571 String.join(" ", tmConfig.getTestJarsList()), 572 getTestModuleContentId( 573 entry, 574 tmConfig.getTestFileNamesList(), 575 tmConfig.getTestJarsList())); 576 } 577 pWriter.flush(); 578 pWriter.close(); 579 } catch (IOException e) { 580 System.err.println("IOException:" + e.getMessage()); 581 } 582 } 583 getFileEntriesList(ReleaseContent relContent)584 public static Collection<Entry> getFileEntriesList(ReleaseContent relContent) { 585 return relContent.getEntries().values(); 586 } 587 588 // get Test Module Content Id = config cid + apk cids + jar cids getTestModuleContentId(Entry config, List<String> apks, List<String> jars)589 private String getTestModuleContentId(Entry config, List<String> apks, List<String> jars) { 590 String id = null; 591 //Starts with config file content_id 592 String idStr = config.getContentId(); 593 try { 594 MessageDigest md = MessageDigest.getInstance("SHA-256"); 595 //Add all apk content_id 596 for (String apk : apks) { 597 idStr += getTestTargetContentId(String.format(TESTCASES_FOLDER_FORMAT, apk)); 598 } 599 //Add all jar content_id 600 for (String jar : jars) { 601 idStr += getTestTargetContentId(String.format(TESTCASES_FOLDER_FORMAT, jar)); 602 } 603 md.update(idStr.getBytes(StandardCharsets.UTF_8)); 604 // Converts to Base64 String 605 id = Base64.getEncoder().encodeToString(md.digest()); 606 // System.out.println("getTestModuleContentId: " + idStr); 607 } catch (NoSuchAlgorithmException e) { 608 System.err.println("NoSuchAlgorithmException:" + e.getMessage()); 609 } 610 return id; 611 } 612 getTestTargetContentId(String targetFile)613 private String getTestTargetContentId(String targetFile) { 614 Entry entry = mRelContent.getEntries().get(targetFile); 615 if (entry != null) { 616 return entry.getContentId(); 617 } else { 618 System.err.println("No getTestTargetContentId: " + targetFile); 619 return ""; 620 } 621 } 622 623 } 624