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.targetprep.ITargetPreparer;
27 import com.android.tradefed.targetprep.PushFilePreparer;
28 import com.android.tradefed.targetprep.TestAppInstallSetup;
29 import com.android.tradefed.testtype.IRemoteTest;
30 import com.android.tradefed.testtype.InstrumentationTest;
31 import com.android.tradefed.util.AaptParser;
32 
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.junit.runners.JUnit4;
36 
37 import java.io.File;
38 import java.io.FilenameFilter;
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45 
46 /**
47  * Class to validate tests Apks in testcases/
48  */
49 @RunWith(JUnit4.class)
50 public class ApkPackageNameCheck {
51 
52     private static final Set<String> EXCEPTION_LIST = new HashSet<>();
53     static {
54         // TODO: Remove exception when their package have been fixed.
55         EXCEPTION_LIST.add("android.app.cts");
56         EXCEPTION_LIST.add("android.systemui.cts");
57     }
58 
59     /**
60      * We ensure that no apk with same package names may be installed. Otherwise it may results in
61      * conflicts.
62      */
63     @Test
testApkPackageNames()64     public void testApkPackageNames() throws Exception {
65         String ctsRoot = System.getProperty("CTS_ROOT");
66         File testcases = new File(ctsRoot, "/android-cts/testcases/");
67         if (!testcases.exists()) {
68             fail(String.format("%s does not exists", testcases));
69             return;
70         }
71         File[] listConfig = testcases.listFiles(new FilenameFilter() {
72             @Override
73             public boolean accept(File dir, String name) {
74                 if (name.endsWith(".config")) {
75                     return true;
76                 }
77                 return false;
78             }
79         });
80         assertTrue(listConfig.length > 0);
81         // We check all apk installed by all modules
82         Map<String, String> packageNames = new HashMap<>();
83 
84         for (File config : listConfig) {
85             IConfiguration c = ConfigurationFactory.getInstance()
86                     .createConfigurationFromArgs(new String[] {config.getAbsolutePath()});
87             // For each config, we check all the apk it's going to install
88             List<File> apkNames = new ArrayList<>();
89             List<String> packageListNames = new ArrayList<>();
90             for (ITargetPreparer prep : c.getTargetPreparers()) {
91                 if (prep instanceof TestAppInstallSetup) {
92                     apkNames.addAll(((TestAppInstallSetup) prep).getTestsFileName());
93                 }
94                 // Ensure the files requested to be pushed exist.
95                 if (prep instanceof FilePusher && ((FilePusher) prep).shouldAppendBitness()) {
96                     for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
97                         String path = f.getPath();
98                         if (!new File(testcases, path + "32").exists()
99                                 || !new File(testcases, path + "64").exists()) {
100                             // TODO: Enforce should abort on failure is True in CTS
101                             if (((FilePusher) prep).shouldAbortOnFailure()) {
102                                 fail(
103                                         String.format(
104                                                 "File %s[32/64] wasn't found in testcases/ while "
105                                                         + "it's expected to be pushed as part of "
106                                                         + "%s",
107                                                 path, config.getName()));
108                             }
109                         }
110                     }
111                 } else if (prep instanceof PushFilePreparer) {
112                     for (File f : ((PushFilePreparer) prep).getPushSpecs(null).values()) {
113                         String path = f.getPath();
114                         if (!new File(testcases, path).exists()) {
115                             // TODO: Enforce should abort on failure is True in CTS
116                             if (((PushFilePreparer) prep).shouldAbortOnFailure()) {
117                                 fail(
118                                         String.format(
119                                                 "File %s wasn't found in testcases/ while it's "
120                                                         + "expected to be pushed as part of %s",
121                                                 path, config.getName()));
122                             }
123                         }
124                     }
125                 }
126             }
127 
128             for (File apk : apkNames) {
129                 String apkName = apk.getName();
130                 File apkFile = new File(testcases, apkName);
131                 if (!apkFile.exists()) {
132                     fail(String.format("Module %s is trying to install %s which does not "
133                             + "exists in testcases/", config.getName(), apkFile));
134                 }
135                 AaptParser res = AaptParser.parse(apkFile);
136                 assertNotNull(res);
137                 String packageName = res.getPackageName();
138                 String put = packageNames.put(packageName, apkName);
139                 packageListNames.add(packageName);
140                 // The package already exists and it's a different apk
141                 if (put != null && !apkName.equals(put) && !EXCEPTION_LIST.contains(packageName)) {
142                     fail(String.format("Module %s: Package name '%s' from apk '%s' was already "
143                             + "added by previous apk '%s'.",
144                             config.getName(), packageName, apkName, put));
145                 }
146             }
147 
148             // Catch a test trying to run something it doesn't install.
149             List<IRemoteTest> tests = c.getTests();
150             for (IRemoteTest test : tests) {
151                 if (test instanceof InstrumentationTest) {
152                     InstrumentationTest instrumentationTest = (InstrumentationTest) test;
153                     if (instrumentationTest.getPackageName() != null) {
154                         if (!packageListNames.contains(instrumentationTest.getPackageName())) {
155                             throw new ConfigurationException(
156                                     String.format("Module %s requests to run '%s' but it's not "
157                                         + "part of any apks.",
158                                         config.getName(), instrumentationTest.getPackageName()));
159                         }
160                     }
161                 }
162             }
163         }
164     }
165 }
166