1 /* 2 * Copyright (C) 2017 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.assertNotNull; 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assert.fail; 21 22 import com.android.compatibility.common.tradefed.targetprep.FilePusher; 23 import com.android.tradefed.config.ConfigurationException; 24 import com.android.tradefed.config.ConfigurationFactory; 25 import com.android.tradefed.config.IConfiguration; 26 import com.android.tradefed.config.IDeviceConfiguration; 27 import com.android.tradefed.targetprep.ITargetPreparer; 28 import com.android.tradefed.targetprep.PushFilePreparer; 29 import com.android.tradefed.targetprep.TestAppInstallSetup; 30 import com.android.tradefed.testtype.IRemoteTest; 31 import com.android.tradefed.testtype.InstrumentationTest; 32 import com.android.tradefed.util.AaptParser; 33 import com.android.tradefed.util.FileUtil; 34 35 import com.google.common.base.Joiner; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.junit.runners.JUnit4; 40 41 import java.io.File; 42 import java.util.ArrayList; 43 import java.util.HashMap; 44 import java.util.HashSet; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Set; 48 49 /** 50 * Class to validate tests Apks in testcases/ 51 */ 52 @RunWith(JUnit4.class) 53 public class ApkPackageNameCheck { 54 55 private static final Set<String> EXCEPTION_LIST = new HashSet<>(); 56 static { 57 // TODO: Remove exception when their package have been fixed. 58 EXCEPTION_LIST.add("android.app.cts"); 59 EXCEPTION_LIST.add("android.systemui.cts"); 60 } 61 62 /** 63 * We ensure that no apk with same package names may be installed. Otherwise it may results in 64 * conflicts. 65 */ 66 @Test testApkPackageNames()67 public void testApkPackageNames() throws Exception { 68 String ctsRoot = System.getProperty("CTS_ROOT"); 69 File testcases = new File(ctsRoot, "/android-cts/testcases/"); 70 if (!testcases.exists()) { 71 fail(String.format("%s does not exists", testcases)); 72 return; 73 } 74 Set<File> listConfigs = FileUtil.findFilesObject(testcases, ".*\\.config"); 75 assertTrue(listConfigs.size() > 0); 76 // We check all apk installed by all modules 77 Map<String, String> packageNames = new HashMap<>(); 78 79 List<String> errors = new ArrayList<>(); 80 81 for (File config : listConfigs) { 82 IConfiguration c = ConfigurationFactory.getInstance() 83 .createConfigurationFromArgs(new String[] {config.getAbsolutePath()}); 84 // For each config, we check all the apk it's going to install 85 List<File> apkNames = new ArrayList<>(); 86 List<String> packageListNames = new ArrayList<>(); 87 for (IDeviceConfiguration dConfig : c.getDeviceConfig()) { 88 for (ITargetPreparer prep : dConfig.getTargetPreparers()) { 89 if (prep instanceof TestAppInstallSetup) { 90 apkNames.addAll(((TestAppInstallSetup) prep).getTestsFileName()); 91 } 92 // Ensure the files requested to be pushed exist. 93 if (prep instanceof FilePusher && ((FilePusher) prep).shouldAppendBitness()) { 94 if (!((FilePusher) prep).shouldAbortOnFailure()) { 95 errors.add(String.format("Config %s should not disable abort-on-push-failure", config.getName())); 96 } 97 for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) { 98 String path = f.getPath(); 99 File file32 = FileUtil.findFile(config.getParentFile(), path + "32"); 100 File file64 = FileUtil.findFile(config.getParentFile(), path + "64"); 101 if (file32 == null || file64 == null) { 102 errors.add( 103 String.format( 104 "File %s[32/64] wasn't found in module " 105 + "dependencies while it's expected to " 106 + "be pushed as part of %s. Make sure " 107 + "that it's added in the Android.bp " 108 + "file of the module under " 109 + "'data_device_bins_both' field.", 110 path, config.getName())); 111 continue; 112 } 113 } 114 } else if (prep instanceof PushFilePreparer) { 115 if (!((PushFilePreparer) prep).shouldAbortOnFailure()) { 116 errors.add(String.format("Config %s should not disable abort-on-push-failure", config.getName())); 117 } 118 for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) { 119 String path = f.getPath(); 120 // Use findFiles to also match top-level dir, which is a valid push spec 121 Set<String> toBePushed = FileUtil.findFiles(config.getParentFile(), 122 path); 123 if (toBePushed.isEmpty()) { 124 errors.add( 125 String.format( 126 "File %s wasn't found in module dependencies " 127 + "while it's expected to be pushed " 128 + "as part of %s. Make sure that it's added in the Android.bp file of the module under 'data' field.", 129 path, config.getName())); 130 continue; 131 } 132 } 133 } 134 } 135 136 // All apks need to be in the config dir or sub-dir 137 for (File apk : apkNames) { 138 String apkName = apk.getName(); 139 File apkFile = FileUtil.findFile(config.getParentFile(), apkName); 140 if (apkFile == null || !apkFile.exists()) { 141 errors.add( 142 String.format("Module %s is trying to install %s which does not " 143 + "exists in testcases/. Make sure that it's added " 144 + "in the Android.bp file of the module under " 145 + "'data' field.", config.getName(), apkName)); 146 continue; 147 } 148 AaptParser res = AaptParser.parse(apkFile); 149 assertNotNull(res); 150 String packageName = res.getPackageName(); 151 String put = packageNames.put(packageName, apkName); 152 packageListNames.add(packageName); 153 // The package already exists and it's a different apk 154 if (put != null && !apkName.equals(put) && !EXCEPTION_LIST.contains(packageName)) { 155 errors.add( 156 String.format("Module %s: Package name '%s' from apk '%s' was " 157 + "already added by previous apk '%s'.", 158 config.getName(), packageName, apkName, put)); 159 continue; 160 } 161 } 162 } 163 // Catch a test trying to run something it doesn't install. 164 List<IRemoteTest> tests = c.getTests(); 165 for (IRemoteTest test : tests) { 166 if (test instanceof InstrumentationTest) { 167 InstrumentationTest instrumentationTest = (InstrumentationTest) test; 168 if (instrumentationTest.getPackageName() != null) { 169 if (!packageListNames.contains(instrumentationTest.getPackageName())) { 170 errors.add( 171 String.format("Module %s requests to run '%s' but it's not " 172 + "part of any apks.", 173 config.getName(), instrumentationTest.getPackageName())); 174 continue; 175 } 176 } 177 } 178 } 179 } 180 if (!errors.isEmpty()) { 181 throw new ConfigurationException(Joiner.on("\n").join(errors)); 182 } 183 } 184 } 185