1#!/usr/bin/python 2 3# Copyright (C) 2009 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Module for generating CTS test descriptions and test plans.""" 18 19import glob 20import os 21import re 22import shutil 23import subprocess 24import sys 25import xml.dom.minidom as dom 26from cts import tools 27from multiprocessing import Pool 28 29def GetSubDirectories(root): 30 """Return all directories under the given root directory.""" 31 return [x for x in os.listdir(root) if os.path.isdir(os.path.join(root, x))] 32 33 34def GetMakeFileVars(makefile_path): 35 """Extracts variable definitions from the given make file. 36 37 Args: 38 makefile_path: Path to the make file. 39 40 Returns: 41 A dictionary mapping variable names to their assigned value. 42 """ 43 result = {} 44 pattern = re.compile(r'^\s*([^:#=\s]+)\s*:=\s*(.*?[^\\])$', re.MULTILINE + re.DOTALL) 45 stream = open(makefile_path, 'r') 46 content = stream.read() 47 for match in pattern.finditer(content): 48 result[match.group(1)] = match.group(2) 49 stream.close() 50 return result 51 52 53class CtsBuilder(object): 54 """Main class for generating test descriptions and test plans.""" 55 56 def __init__(self, argv): 57 """Initialize the CtsBuilder from command line arguments.""" 58 if len(argv) != 6: 59 print 'Usage: %s <testRoot> <ctsOutputDir> <tempDir> <androidRootDir> <docletPath>' % argv[0] 60 print '' 61 print 'testRoot: Directory under which to search for CTS tests.' 62 print 'ctsOutputDir: Directory in which the CTS repository should be created.' 63 print 'tempDir: Directory to use for storing temporary files.' 64 print 'androidRootDir: Root directory of the Android source tree.' 65 print 'docletPath: Class path where the DescriptionGenerator doclet can be found.' 66 sys.exit(1) 67 self.test_root = sys.argv[1] 68 self.out_dir = sys.argv[2] 69 self.temp_dir = sys.argv[3] 70 self.android_root = sys.argv[4] 71 self.doclet_path = sys.argv[5] 72 73 self.test_repository = os.path.join(self.out_dir, 'repository/testcases') 74 self.plan_repository = os.path.join(self.out_dir, 'repository/plans') 75 76 #dirty hack to copy over prepopulated CTS test plans, stable vs flaky, for autoCTS 77 self.definedplans_repository = os.path.join(self.android_root, 'cts/tests/plans') 78 79 def GenerateTestDescriptions(self): 80 """Generate test descriptions for all packages.""" 81 pool = Pool(processes=2) 82 83 # individually generate descriptions not following conventions 84 pool.apply_async(GenerateSignatureCheckDescription, [self.test_repository]) 85 86 # generate test descriptions for android tests 87 results = [] 88 pool.close() 89 pool.join() 90 return sum(map(lambda result: result.get(), results)) 91 92 def __WritePlan(self, plan, plan_name): 93 print 'Generating test plan %s' % plan_name 94 plan.Write(os.path.join(self.plan_repository, plan_name + '.xml')) 95 96 def GenerateTestPlans(self): 97 """Generate default test plans.""" 98 # TODO: Instead of hard-coding the plans here, use a configuration file, 99 # such as test_defs.xml 100 packages = [] 101 descriptions = sorted(glob.glob(os.path.join(self.test_repository, '*.xml'))) 102 for description in descriptions: 103 doc = tools.XmlFile(description) 104 packages.append(doc.GetAttr('TestPackage', 'appPackageName')) 105 # sort the list to give the same sequence based on name 106 packages.sort() 107 108 plan = tools.TestPlan(packages) 109 plan.Exclude('android\.performance.*') 110 self.__WritePlan(plan, 'CTS') 111 self.__WritePlan(plan, 'CTS-TF') 112 113 plan = tools.TestPlan(packages) 114 plan.Exclude('android\.performance.*') 115 plan.Exclude('android\.media\.cts\.StreamingMediaPlayerTest.*') 116 # Test plan to not include media streaming tests 117 self.__WritePlan(plan, 'CTS-No-Media-Stream') 118 119 plan = tools.TestPlan(packages) 120 plan.Exclude('android\.performance.*') 121 self.__WritePlan(plan, 'SDK') 122 123 plan.Exclude(r'android\.tests\.sigtest') 124 plan.Exclude(r'android\.core.*') 125 self.__WritePlan(plan, 'Android') 126 127 plan = tools.TestPlan(packages) 128 plan.Include(r'android\.core\.tests.*') 129 self.__WritePlan(plan, 'Java') 130 131 plan = tools.TestPlan(packages) 132 plan.Include(r'android\.core\.vm-tests-tf') 133 self.__WritePlan(plan, 'VM-TF') 134 135 plan = tools.TestPlan(packages) 136 plan.Include(r'android\.tests\.sigtest') 137 self.__WritePlan(plan, 'Signature') 138 139 plan = tools.TestPlan(packages) 140 plan.Include(r'android\.tests\.appsecurity') 141 self.__WritePlan(plan, 'AppSecurity') 142 143 # hard-coded white list for PDK plan 144 plan.Exclude('.*') 145 plan.Include('android\.aadb') 146 plan.Include('android\.bluetooth') 147 plan.Include('android\.graphics.*') 148 plan.Include('android\.hardware') 149 plan.Include('android\.media') 150 plan.Exclude('android\.mediastress') 151 plan.Include('android\.net') 152 plan.Include('android\.opengl.*') 153 plan.Include('android\.renderscript') 154 plan.Include('android\.telephony') 155 plan.Include('android\.nativemedia.*') 156 plan.Include('com\.android\.cts\..*')#TODO(stuartscott): Should PDK have all these? 157 #TODO(stuartscott): Maybe move away from com.android.* to android.* - less typing 158 self.__WritePlan(plan, 'PDK') 159 160 #dirty hack to copy over pre-populated CTS plans - flaky vs stable - to streamline autoCTS 161 shutil.copyfile(os.path.join(self.definedplans_repository, 'CTS-flaky.xml'), 162 os.path.join(self.plan_repository, 'CTS-flaky.xml')) 163 shutil.copyfile(os.path.join(self.definedplans_repository, 'CTS-stable.xml'), 164 os.path.join(self.plan_repository, 'CTS-stable.xml')) 165 166def LogGenerateDescription(name): 167 print 'Generating test description for package %s' % name 168 169def GenerateSignatureCheckDescription(test_repository): 170 """Generate the test description for the signature check.""" 171 LogGenerateDescription('android.tests.sigtest') 172 package = tools.TestPackage('SignatureTest', 'android.tests.sigtest') 173 package.AddAttribute('appNameSpace', 'android.tests.sigtest') 174 package.AddAttribute('signatureCheck', 'true') 175 package.AddAttribute('runner', '.InstrumentationRunner') 176 package.AddTest('android.tests.sigtest.SignatureTest.testSignature') 177 description = open(os.path.join(test_repository, 'SignatureTest.xml'), 'w') 178 package.WriteDescription(description) 179 description.close() 180 181if __name__ == '__main__': 182 builder = CtsBuilder(sys.argv) 183 result = builder.GenerateTestDescriptions() 184 if result != 0: 185 sys.exit(result) 186 builder.GenerateTestPlans() 187 188