• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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