普通文本  |  341行  |  12 KB

#!/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()