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.content.cts"); 60 // TODO(b/290634145): Refactor WM CTS into fully isolated modules 61 EXCEPTION_LIST.add("android.server.wm.cts"); 62 EXCEPTION_LIST.add("android.systemui.cts"); 63 // TODO(b/331566031): Remove exception when the test owner 64 // split the CTS and MCTS into different modules. 65 EXCEPTION_LIST.add("android.mediav2.cts"); 66 EXCEPTION_LIST.add("android.media.bettertogether.cts"); 67 EXCEPTION_LIST.add("android.media.codec.cts"); 68 EXCEPTION_LIST.add("android.media.drmframework.cts"); 69 EXCEPTION_LIST.add("android.media.encoder.cts"); 70 EXCEPTION_LIST.add("android.media.extractor.cts"); 71 EXCEPTION_LIST.add("android.media.misc.cts"); 72 EXCEPTION_LIST.add("android.media.muxer.cts"); 73 EXCEPTION_LIST.add("android.media.player.cts"); 74 EXCEPTION_LIST.add("android.media.recorder.cts"); 75 EXCEPTION_LIST.add("android.media.mediaparser.cts"); 76 EXCEPTION_LIST.add("android.mediastress.cts"); 77 EXCEPTION_LIST.add("android.media.mediatranscoding.cts"); 78 EXCEPTION_LIST.add("android.view.textclassifier.cts"); 79 EXCEPTION_LIST.add("android.appsecurity.cts"); 80 } 81 82 /** 83 * We ensure that no apk with same package names may be installed. Otherwise it may results in 84 * conflicts. 85 */ 86 @Test testApkPackageNames()87 public void testApkPackageNames() throws Exception { 88 String ctsRoot = System.getProperty("CTS_ROOT"); 89 File testcases = new File(ctsRoot, "/android-cts/testcases/"); 90 if (!testcases.exists()) { 91 fail(String.format("%s does not exists", testcases)); 92 return; 93 } 94 Set<File> listConfigs = FileUtil.findFilesObject(testcases, ".*\\.config"); 95 assertTrue(listConfigs.size() > 0); 96 // We check all apk installed by all modules 97 Map<String, String> packageNames = new HashMap<>(); 98 99 List<String> errors = new ArrayList<>(); 100 101 for (File config : listConfigs) { 102 IConfiguration c = ConfigurationFactory.getInstance() 103 .createConfigurationFromArgs(new String[] {config.getAbsolutePath()}); 104 // For each config, we check all the apk it's going to install 105 List<File> apkNames = new ArrayList<>(); 106 List<String> packageListNames = new ArrayList<>(); 107 for (IDeviceConfiguration dConfig : c.getDeviceConfig()) { 108 for (ITargetPreparer prep : dConfig.getTargetPreparers()) { 109 if (prep instanceof TestAppInstallSetup) { 110 apkNames.addAll(((TestAppInstallSetup) prep).getTestsFileName()); 111 } 112 // Ensure the files requested to be pushed exist. 113 if (prep instanceof FilePusher && ((FilePusher) prep).shouldAppendBitness()) { 114 if (!((FilePusher) prep).shouldAbortOnFailure()) { 115 errors.add(String.format("Config %s should not disable abort-on-push-failure", config.getName())); 116 } 117 for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) { 118 String path = f.getPath(); 119 File file32 = FileUtil.findFile(config.getParentFile(), path + "32"); 120 File file64 = FileUtil.findFile(config.getParentFile(), path + "64"); 121 if (file32 == null || file64 == null) { 122 errors.add( 123 String.format( 124 "File %s[32/64] wasn't found in module " 125 + "dependencies while it's expected to " 126 + "be pushed as part of %s. Make sure " 127 + "that it's added in the Android.bp " 128 + "file of the module under " 129 + "'data_device_bins_both' field.", 130 path, config.getName())); 131 continue; 132 } 133 } 134 } else if (prep instanceof PushFilePreparer) { 135 if (!((PushFilePreparer) prep).shouldAbortOnFailure()) { 136 errors.add(String.format("Config %s should not disable abort-on-push-failure", config.getName())); 137 } 138 for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) { 139 String path = f.getPath(); 140 // Use findFiles to also match top-level dir, which is a valid push spec 141 Set<String> toBePushed = FileUtil.findFiles(config.getParentFile(), 142 path); 143 if (toBePushed.isEmpty()) { 144 errors.add( 145 String.format( 146 "File %s wasn't found in module dependencies " 147 + "while it's expected to be pushed " 148 + "as part of %s. Make sure that it's added in the Android.bp file of the module under 'data' field.", 149 path, config.getName())); 150 continue; 151 } 152 } 153 } 154 } 155 156 // All apks need to be in the config dir or sub-dir 157 for (File apk : apkNames) { 158 String apkName = apk.getName(); 159 File apkFile = FileUtil.findFile(config.getParentFile(), apkName); 160 if (apkFile == null || !apkFile.exists()) { 161 errors.add( 162 String.format("Module %s is trying to install %s which does not " 163 + "exists in testcases/. Make sure that it's added " 164 + "in the Android.bp file of the module under " 165 + "'data' field.", config.getName(), apkName)); 166 continue; 167 } 168 AaptParser res = AaptParser.parse(apkFile); 169 assertNotNull(res); 170 String packageName = res.getPackageName(); 171 String put = packageNames.put(packageName, apkName); 172 packageListNames.add(packageName); 173 // The package already exists and it's a different apk 174 if (put != null && !apkName.equals(put) && !EXCEPTION_LIST.contains(packageName)) { 175 errors.add( 176 String.format("Module %s: Package name '%s' from apk '%s' was " 177 + "already added by previous apk '%s'.", 178 config.getName(), packageName, apkName, put)); 179 continue; 180 } 181 } 182 } 183 // Catch a test trying to run something it doesn't install. 184 List<IRemoteTest> tests = c.getTests(); 185 for (IRemoteTest test : tests) { 186 if (test instanceof InstrumentationTest) { 187 InstrumentationTest instrumentationTest = (InstrumentationTest) test; 188 if (instrumentationTest.getPackageName() != null) { 189 if (!packageListNames.contains(instrumentationTest.getPackageName())) { 190 errors.add( 191 String.format("Module %s requests to run '%s' but it's not " 192 + "part of any apks.", 193 config.getName(), instrumentationTest.getPackageName())); 194 continue; 195 } 196 } 197 } 198 } 199 } 200 if (!errors.isEmpty()) { 201 throw new ConfigurationException(Joiner.on("\n").join(errors)); 202 } 203 } 204 } 205