• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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