#!/usr/bin/env python # # Copyright 2016 - The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Initiate a test case directory. # This script copy a template which contains Android.mk, __init__.py files, # AndroidTest.xml and a test case python file into a given relative directory # under testcases/ using the given test name. import os import sys import datetime import re import shutil import argparse VTS_PATH = 'test/vts' VTS_TEST_CASE_PATH = os.path.join(VTS_PATH, 'testcases') PYTHON_INIT_FILE_NAME = '__init__.py' ANDROID_MK_FILE_NAME = 'Android.mk' ANDROID_TEST_XML_FILE_NAME = 'AndroidTest.xml' class TestCaseCreator(object): '''Init a test case directory with helloworld test case. Attributes: test_name: string, test case name in UpperCamel build_top: string, equal to environment variable ANDROID_BUILD_TOP test_dir: string, test case absolute directory test_name: string, test case name in UpperCamel test_plan: string, the plan that the test belongs to test_type: test type, such as HidlHalTest, HostDrivenTest, etc current_year: current year vts_test_case_dir: absolute dir of vts testcases directory ''' def __init__(self, test_name, test_plan, test_dir_under_testcases, test_type): '''Initialize class attributes. Args: test_name: string, test case name in UpperCamel test_plan: string, the plan that the test belongs to test_dir_under_testcases: string, test case relative directory under test/vts/testcases. ''' if not test_dir_under_testcases: print 'Error: Empty test directory entered. Exiting' sys.exit(3) test_dir_under_testcases = os.path.normpath( test_dir_under_testcases.strip()) if not self.IsUpperCamel(test_name): print 'Error: Test name not in UpperCamel case. Exiting' sys.exit(4) self.test_name = test_name if not test_plan: self.test_plan = 'vts-misc' else: self.test_plan = test_plan if not test_type: self.test_type = 'HidlHalTest' else: self.test_type = test_type self.build_top = os.getenv('ANDROID_BUILD_TOP') if not self.build_top: print('Error: Missing ANDROID_BUILD_TOP env variable. Please run ' '\'. build/envsetup.sh; lunch <build target>\' Exiting...') sys.exit(1) self.vts_test_case_dir = os.path.abspath( os.path.join(self.build_top, VTS_TEST_CASE_PATH)) self.test_dir = os.path.abspath( os.path.join(self.vts_test_case_dir, test_dir_under_testcases)) self.current_year = datetime.datetime.now().year def InitTestCaseDir(self): '''Start init test case directory''' if os.path.exists(self.test_dir): print 'Error: Test directory already exists. Exiting...' sys.exit(2) try: os.makedirs(self.test_dir) except: print('Error: Failed to create test directory at %s. ' 'Exiting...' % self.test_dir) sys.exit(2) self.CreatePythonInitFile() self.CreateAndroidMk() self.CreateAndroidTestXml() self.CreateTestCasePy() def UpperCamelToLowerUnderScore(self, name): '''Convert UpperCamel name to lower_under_score name. Args: name: string in UpperCamel. Returns: a lower_under_score version of the given name ''' return re.sub('(?!^)([A-Z]+)', r'_\1', name).lower() def IsUpperCamel(self, name): '''Check whether a given name is UpperCamel case. Args: name: string. Returns: True if name is in UpperCamel case, False otherwise ''' regex = re.compile('((?:[A-Z][a-z]+)[0-9]*)+') match = regex.match(name) return match and (match.end() - match.start() == len(name)) def CreatePythonInitFile(self): '''Populate test case directory and parent directories with __init__.py. ''' if not self.test_dir.startswith(self.vts_test_case_dir): print 'Error: Test case directory is not under VTS test case directory.' sys.exit(4) path = self.test_dir while not path == self.vts_test_case_dir: target = os.path.join(path, PYTHON_INIT_FILE_NAME) if not os.path.exists(target): print 'Creating %s' % target with open(target, 'w') as f: pass path = os.path.dirname(path) def CreateAndroidMk(self): '''Populate test case directory and parent directories with Android.mk ''' vts_dir = os.path.join(self.build_top, VTS_PATH) target = os.path.join(self.test_dir, ANDROID_MK_FILE_NAME) with open(target, 'w') as f: print 'Creating %s' % target f.write(LICENSE_STATEMENT_POUND.format(year=self.current_year)) f.write('\n') f.write( ANDROID_MK_TEMPLATE.format( test_name=self.test_name, config_src_dir=self.test_dir[len(vts_dir) + 1:])) path = self.test_dir while not path == vts_dir: target = os.path.join(path, ANDROID_MK_FILE_NAME) if not os.path.exists(target): print 'Creating %s' % target with open(target, 'w') as f: f.write( LICENSE_STATEMENT_POUND.format(year=self.current_year)) f.write(ANDROID_MK_CALL_SUB) path = os.path.dirname(path) def CreateAndroidTestXml(self): '''Create AndroidTest.xml''' target = os.path.join(self.test_dir, ANDROID_TEST_XML_FILE_NAME) with open(target, 'w') as f: print 'Creating %s' % target f.write(XML_HEADER) f.write(LICENSE_STATEMENT_XML.format(year=self.current_year)) f.write( ANDROID_TEST_XML_TEMPLATE.format( test_name=self.test_name, test_plan=self.test_plan, test_type=self.test_type, test_path_under_vts=self.test_dir[ len(os.path.join(self.build_top, VTS_PATH)) + 1:], test_case_file_without_extension=self.test_name)) def CreateTestCasePy(self): '''Create <test_case_name>.py''' target = os.path.join(self.test_dir, '%s.py' % self.test_name) with open(target, 'w') as f: print 'Creating %s' % target f.write(PY_HEADER) f.write(LICENSE_STATEMENT_POUND.format(year=self.current_year)) f.write('\n') f.write(TEST_CASE_PY_TEMPLATE.format(test_name=self.test_name)) def main(): parser = argparse.ArgumentParser(description='Initiate a test case.') parser.add_argument( '--name', dest='test_name', required=True, help='Test case name in UpperCamel. Example: VtsKernelLtp') parser.add_argument( '--plan', dest='test_plan', required=False, help='The plan that the test belongs to. Example: vts-kernel') parser.add_argument( '--dir', dest='test_dir', required=True, help='Test case relative directory under test/vts/testcses.') parser.add_argument( '--type', dest='test_type', required=False, help='Test type, such as HidlHalTest, HostDrivenTest, etc.') args = parser.parse_args() test_case_creater = TestCaseCreator(args.test_name, args.test_plan, args.test_dir, args.test_type) test_case_creater.InitTestCaseDir() LICENSE_STATEMENT_POUND = '''# # Copyright (C) {year} The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ''' LICENSE_STATEMENT_XML = '''<!-- Copyright (C) {year} The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> ''' ANDROID_MK_TEMPLATE = '''LOCAL_PATH := $(call my-dir) include $(call all-subdir-makefiles) include $(CLEAR_VARS) LOCAL_MODULE := {test_name} include test/vts/tools/build/Android.host_config.mk ''' ANDROID_MK_CALL_SUB = '''LOCAL_PATH := $(call my-dir) include $(call all-subdir-makefiles) ''' XML_HEADER = '''<?xml version="1.0" encoding="utf-8"?> ''' ANDROID_TEST_XML_TEMPLATE = '''<configuration description="Config for VTS {test_name} test cases"> <option name="config-descriptor:metadata" key="plan" value="{test_plan}" /> <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher"> <option name="push-group" value="{test_type}.push" /> </target_preparer> <test class="com.android.tradefed.testtype.VtsMultiDeviceTest"> <option name="test-module-name" value="{test_name}" /> <option name="test-case-path" value="vts/{test_path_under_vts}/{test_case_file_without_extension}" /> </test> </configuration> ''' PY_HEADER = '''#!/usr/bin/env python ''' TEST_CASE_PY_TEMPLATE = '''import logging from vts.runners.host import asserts from vts.runners.host import base_test from vts.runners.host import const from vts.runners.host import test_runner class {test_name}(base_test.BaseTestClass): """Two hello world test cases which use the shell driver.""" def setUpClass(self): self.dut = self.android_devices[0] self.shell = self.dut.shell def testEcho1(self): """A simple testcase which sends a command.""" results = self.shell.Execute("echo hello_world") # runs a shell command. logging.info(str(results[const.STDOUT])) # prints the stdout asserts.assertEqual(results[const.STDOUT][0].strip(), "hello_world") # checks the stdout asserts.assertEqual(results[const.EXIT_CODE][0], 0) # checks the exit code def testEcho2(self): """A simple testcase which sends two commands.""" results = self.shell.Execute(["echo hello", "echo world"]) logging.info(str(results[const.STDOUT])) asserts.assertEqual(len(results[const.STDOUT]), 2) # check the number of processed commands asserts.assertEqual(results[const.STDOUT][0].strip(), "hello") asserts.assertEqual(results[const.STDOUT][1].strip(), "world") asserts.assertEqual(results[const.EXIT_CODE][0], 0) asserts.assertEqual(results[const.EXIT_CODE][1], 0) if __name__ == "__main__": test_runner.main() ''' if __name__ == '__main__': main()