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