1#!/usr/bin/env python 2# 3# Copyright 2016 - 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 18# Initiate a test case directory. 19# This script copy a template which contains Android.mk, __init__.py files, 20# AndroidTest.xml and a test case python file into a given relative directory 21# under testcases/ using the given test name. 22 23import os 24import sys 25import datetime 26import re 27import shutil 28import argparse 29 30VTS_PATH = 'test/vts' 31VTS_TEST_CASE_PATH = os.path.join(VTS_PATH, 'testcases') 32PYTHON_INIT_FILE_NAME = '__init__.py' 33ANDROID_MK_FILE_NAME = 'Android.mk' 34ANDROID_TEST_XML_FILE_NAME = 'AndroidTest.xml' 35 36 37class TestCaseCreator(object): 38 '''Init a test case directory with helloworld test case. 39 40 Attributes: 41 test_name: string, test case name in UpperCamel 42 build_top: string, equal to environment variable ANDROID_BUILD_TOP 43 test_dir: string, test case absolute directory 44 test_name: string, test case name in UpperCamel 45 test_type: test type, such as HidlHalTest, HostDrivenTest, etc 46 current_year: current year 47 vts_test_case_dir: absolute dir of vts testcases directory 48 ''' 49 50 def __init__(self, test_name, test_dir_under_testcases, test_type): 51 '''Initialize class attributes. 52 53 Args: 54 test_name: string, test case name in UpperCamel 55 test_dir_under_testcases: string, test case relative directory under 56 test/vts/testcases. 57 ''' 58 if not test_dir_under_testcases: 59 print 'Error: Empty test directory entered. Exiting' 60 sys.exit(3) 61 test_dir_under_testcases = os.path.normpath( 62 test_dir_under_testcases.strip()) 63 64 if not self.IsUpperCamel(test_name): 65 print 'Error: Test name not in UpperCamel case. Exiting' 66 sys.exit(4) 67 self.test_name = test_name 68 69 if not test_type: 70 self.test_type = 'HidlHalTest' 71 else: 72 self.test_type = test_type 73 74 self.build_top = os.getenv('ANDROID_BUILD_TOP') 75 if not self.build_top: 76 print('Error: Missing ANDROID_BUILD_TOP env variable. Please run ' 77 '\'. build/envsetup.sh; lunch <build target>\' Exiting...') 78 sys.exit(1) 79 80 self.vts_test_case_dir = os.path.abspath( 81 os.path.join(self.build_top, VTS_TEST_CASE_PATH)) 82 83 self.test_dir = os.path.abspath( 84 os.path.join(self.vts_test_case_dir, test_dir_under_testcases)) 85 86 self.current_year = datetime.datetime.now().year 87 88 def InitTestCaseDir(self): 89 '''Start init test case directory''' 90 if os.path.exists(self.test_dir): 91 print 'Error: Test directory already exists. Exiting...' 92 sys.exit(2) 93 try: 94 os.makedirs(self.test_dir) 95 except: 96 print('Error: Failed to create test directory at %s. ' 97 'Exiting...' % self.test_dir) 98 sys.exit(2) 99 100 self.CreatePythonInitFile() 101 self.CreateAndroidMk() 102 self.CreateAndroidTestXml() 103 self.CreateTestCasePy() 104 105 def UpperCamelToLowerUnderScore(self, name): 106 '''Convert UpperCamel name to lower_under_score name. 107 108 Args: 109 name: string in UpperCamel. 110 111 Returns: 112 a lower_under_score version of the given name 113 ''' 114 return re.sub('(?!^)([A-Z]+)', r'_\1', name).lower() 115 116 def IsUpperCamel(self, name): 117 '''Check whether a given name is UpperCamel case. 118 119 Args: 120 name: string. 121 122 Returns: 123 True if name is in UpperCamel case, False otherwise 124 ''' 125 regex = re.compile('((?:[A-Z][a-z]+)[0-9]*)+') 126 match = regex.match(name) 127 return match and (match.end() - match.start() == len(name)) 128 129 def CreatePythonInitFile(self): 130 '''Populate test case directory and parent directories with __init__.py. 131 ''' 132 if not self.test_dir.startswith(self.vts_test_case_dir): 133 print 'Error: Test case directory is not under VTS test case directory.' 134 sys.exit(4) 135 136 path = self.test_dir 137 while not path == self.vts_test_case_dir: 138 target = os.path.join(path, PYTHON_INIT_FILE_NAME) 139 if not os.path.exists(target): 140 print 'Creating %s' % target 141 with open(target, 'w') as f: 142 pass 143 path = os.path.dirname(path) 144 145 def CreateAndroidMk(self): 146 '''Populate test case directory and parent directories with Android.mk 147 ''' 148 vts_dir = os.path.join(self.build_top, VTS_PATH) 149 150 target = os.path.join(self.test_dir, ANDROID_MK_FILE_NAME) 151 with open(target, 'w') as f: 152 print 'Creating %s' % target 153 f.write(LICENSE_STATEMENT_POUND.format(year=self.current_year)) 154 f.write('\n') 155 f.write( 156 ANDROID_MK_TEMPLATE.format( 157 test_name=self.test_name, 158 config_src_dir=self.test_dir[len(vts_dir) + 1:])) 159 160 path = self.test_dir 161 while not path == vts_dir: 162 target = os.path.join(path, ANDROID_MK_FILE_NAME) 163 if not os.path.exists(target): 164 print 'Creating %s' % target 165 with open(target, 'w') as f: 166 f.write( 167 LICENSE_STATEMENT_POUND.format(year=self.current_year)) 168 f.write(ANDROID_MK_CALL_SUB) 169 path = os.path.dirname(path) 170 171 def CreateAndroidTestXml(self): 172 '''Create AndroidTest.xml''' 173 target = os.path.join(self.test_dir, ANDROID_TEST_XML_FILE_NAME) 174 with open(target, 'w') as f: 175 print 'Creating %s' % target 176 f.write(XML_HEADER) 177 f.write(LICENSE_STATEMENT_XML.format(year=self.current_year)) 178 f.write( 179 ANDROID_TEST_XML_TEMPLATE.format( 180 test_name=self.test_name, 181 test_type=self.test_type, 182 test_path_under_vts=self.test_dir[ 183 len(os.path.join(self.build_top, VTS_PATH)) + 1:], 184 test_case_file_without_extension=self.test_name)) 185 186 def CreateTestCasePy(self): 187 '''Create <test_case_name>.py''' 188 target = os.path.join(self.test_dir, '%s.py' % self.test_name) 189 with open(target, 'w') as f: 190 print 'Creating %s' % target 191 f.write(PY_HEADER) 192 f.write(LICENSE_STATEMENT_POUND.format(year=self.current_year)) 193 f.write('\n') 194 f.write(TEST_CASE_PY_TEMPLATE.format(test_name=self.test_name)) 195 196 197def main(): 198 parser = argparse.ArgumentParser(description='Initiate a test case.') 199 parser.add_argument( 200 '--name', 201 dest='test_name', 202 required=True, 203 help='Test case name in UpperCamel. Example: VtsKernelLtp') 204 parser.add_argument( 205 '--dir', 206 dest='test_dir', 207 required=True, 208 help='Test case relative directory under test/vts/testcses.') 209 parser.add_argument( 210 '--type', 211 dest='test_type', 212 required=False, 213 help='Test type, such as HidlHalTest, HostDrivenTest, etc.') 214 215 args = parser.parse_args() 216 test_case_creater = TestCaseCreator(args.test_name, args.test_dir, 217 args.test_type) 218 test_case_creater.InitTestCaseDir() 219 220 221LICENSE_STATEMENT_POUND = '''# 222# Copyright (C) {year} The Android Open Source Project 223# 224# Licensed under the Apache License, Version 2.0 (the "License"); 225# you may not use this file except in compliance with the License. 226# You may obtain a copy of the License at 227# 228# http://www.apache.org/licenses/LICENSE-2.0 229# 230# Unless required by applicable law or agreed to in writing, software 231# distributed under the License is distributed on an "AS IS" BASIS, 232# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 233# See the License for the specific language governing permissions and 234# limitations under the License. 235# 236''' 237 238LICENSE_STATEMENT_XML = '''<!-- Copyright (C) {year} The Android Open Source Project 239 240 Licensed under the Apache License, Version 2.0 (the "License"); 241 you may not use this file except in compliance with the License. 242 You may obtain a copy of the License at 243 244 http://www.apache.org/licenses/LICENSE-2.0 245 246 Unless required by applicable law or agreed to in writing, software 247 distributed under the License is distributed on an "AS IS" BASIS, 248 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 249 See the License for the specific language governing permissions and 250 limitations under the License. 251--> 252''' 253 254ANDROID_MK_TEMPLATE = '''LOCAL_PATH := $(call my-dir) 255 256include $(call all-subdir-makefiles) 257 258include $(CLEAR_VARS) 259 260LOCAL_MODULE := {test_name} 261VTS_CONFIG_SRC_DIR := {config_src_dir} 262include test/vts/tools/build/Android.host_config.mk 263''' 264 265ANDROID_MK_CALL_SUB = '''LOCAL_PATH := $(call my-dir) 266 267include $(call all-subdir-makefiles) 268''' 269 270XML_HEADER = '''<?xml version="1.0" encoding="utf-8"?> 271''' 272 273ANDROID_TEST_XML_TEMPLATE = '''<configuration description="Config for VTS {test_name} test cases"> 274 <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher"> 275 <option name="push-group" value="{test_type}.push" /> 276 </target_preparer> 277 <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer"> 278 </target_preparer> 279 <test class="com.android.tradefed.testtype.VtsMultiDeviceTest"> 280 <option name="test-module-name" value="{test_name}" /> 281 <option name="test-case-path" value="vts/{test_path_under_vts}/{test_case_file_without_extension}" /> 282 </test> 283</configuration> 284''' 285 286PY_HEADER = '''#!/usr/bin/env python 287''' 288 289TEST_CASE_PY_TEMPLATE = '''import logging 290 291from vts.runners.host import asserts 292from vts.runners.host import base_test 293from vts.runners.host import const 294from vts.runners.host import test_runner 295 296 297 298class {test_name}(base_test.BaseTestClass): 299 """Two hello world test cases which use the shell driver.""" 300 301 def setUpClass(self): 302 self.dut = self.android_devices[0] 303 self.shell = self.dut.shell 304 305 def testEcho1(self): 306 """A simple testcase which sends a command.""" 307 results = self.shell.Execute("echo hello_world") # runs a shell command. 308 logging.info(str(results[const.STDOUT])) # prints the stdout 309 asserts.assertEqual(results[const.STDOUT][0].strip(), "hello_world") # checks the stdout 310 asserts.assertEqual(results[const.EXIT_CODE][0], 0) # checks the exit code 311 312 def testEcho2(self): 313 """A simple testcase which sends two commands.""" 314 results = self.shell.Execute(["echo hello", "echo world"]) 315 logging.info(str(results[const.STDOUT])) 316 asserts.assertEqual(len(results[const.STDOUT]), 2) # check the number of processed commands 317 asserts.assertEqual(results[const.STDOUT][0].strip(), "hello") 318 asserts.assertEqual(results[const.STDOUT][1].strip(), "world") 319 asserts.assertEqual(results[const.EXIT_CODE][0], 0) 320 asserts.assertEqual(results[const.EXIT_CODE][1], 0) 321 322 323if __name__ == "__main__": 324 test_runner.main() 325''' 326 327if __name__ == '__main__': 328 main() 329