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 package com.android.compatibility.common.tradefed.presubmit; 17 18 import static org.junit.Assert.fail; 19 20 import com.android.tradefed.config.ConfigurationException; 21 22 import com.google.common.collect.ImmutableSet; 23 24 import org.junit.Test; 25 import org.junit.runner.RunWith; 26 import org.junit.runners.JUnit4; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.Enumeration; 32 import java.util.LinkedHashMap; 33 import java.util.LinkedList; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.jar.JarEntry; 38 import java.util.jar.JarFile; 39 40 /** 41 * Test to check for duplicate files in different jars and prevent the same dependencies of being 42 * included several time (which might result in version conflicts). 43 */ 44 @RunWith(JUnit4.class) 45 public class DupFileTest { 46 47 // We ignore directories part of the common java and google packages. 48 private static final String[] IGNORE_DIRS = 49 new String[] { 50 "android/", 51 "javax/annotation/", 52 "com/google/protobuf/", 53 "kotlin/", 54 "perfetto/protos/" 55 }; 56 // Temporarily exclude some Tradefed jar while we work on unbundling them. 57 private static final Set<String> IGNORE_JARS = ImmutableSet.of("tradefed-test-framework.jar"); 58 59 /** test if there are duplicate files in different jars. */ 60 @Test testDupFilesExist()61 public void testDupFilesExist() throws Exception { 62 // Get list of jars. 63 List<File> jars = getListOfBuiltJars(); 64 65 // Create map of files to jars. 66 Map<String, List<String>> filesToJars = getMapOfFilesAndJars(jars); 67 68 // Check if there are any files with the same name in diff jars. 69 int dupedFiles = 0; 70 StringBuilder dupedFilesSummary = new StringBuilder(); 71 for (Map.Entry<String, List<String>> entry : filesToJars.entrySet()) { 72 String file = entry.getKey(); 73 List<String> jarFiles = entry.getValue(); 74 75 if (jarFiles.size() != 1) { 76 dupedFiles++; 77 dupedFilesSummary.append(file + ": " + jarFiles.toString() + "\n"); 78 } 79 } 80 81 if (dupedFiles != 0) { 82 fail( 83 String.format( 84 "%d files are duplicated in different jars:\n%s", 85 dupedFiles, dupedFilesSummary.toString())); 86 } 87 } 88 89 /** Create map of file to jars */ getMapOfFilesAndJars(List<File> jars)90 private Map<String, List<String>> getMapOfFilesAndJars(List<File> jars) throws IOException { 91 Map<String, List<String>> map = new LinkedHashMap<String, List<String>>(); 92 JarFile jarFile; 93 List<String> jarFileList; 94 // Map all the files from all the jars. 95 for (File jar : jars) { 96 if (IGNORE_JARS.contains(jar.getName())) { 97 continue; 98 } 99 jarFile = new JarFile(jar); 100 jarFileList = getListOfFiles(jarFile); 101 jarFile.close(); 102 103 // Add in the jar file to the map. 104 for (String file : jarFileList) { 105 if (!map.containsKey(file)) { 106 map.put(file, new LinkedList<String>()); 107 } 108 109 map.get(file).add(jar.getName()); 110 } 111 } 112 return map; 113 } 114 115 /** Get the list of jars specified in the path. */ getListOfBuiltJars()116 private List<File> getListOfBuiltJars() throws ConfigurationException { 117 String classpathStr = System.getProperty("java.class.path"); 118 if (classpathStr == null) { 119 throw new ConfigurationException( 120 "Could not find the classpath property: java.class.path"); 121 } 122 List<File> listOfJars = new ArrayList<File>(); 123 for (String jar : classpathStr.split(":")) { 124 File jarFile = new File(jar); 125 if (jarFile.exists()) { 126 listOfJars.add(jarFile); 127 } 128 } 129 return listOfJars; 130 } 131 132 /** Return the list of files in the jar. */ getListOfFiles(JarFile jar)133 private List<String> getListOfFiles(JarFile jar) { 134 List<String> files = new ArrayList<String>(); 135 Enumeration<JarEntry> e = jar.entries(); 136 while (e.hasMoreElements()) { 137 JarEntry entry = e.nextElement(); 138 String filename = entry.getName(); 139 if (checkThisFile(filename)) { 140 files.add(filename); 141 } 142 } 143 return files; 144 } 145 146 /** Check if we should add this file to list of files. We only want to check for classes. */ checkThisFile(String filename)147 private Boolean checkThisFile(String filename) { 148 if (!filename.endsWith(".class")) { 149 return false; 150 } 151 152 for (String skipDir : IGNORE_DIRS) { 153 if (filename.startsWith(skipDir)) { 154 return false; 155 } 156 } 157 158 return true; 159 } 160 } 161