• 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(
154                LICENSE_STATEMENT_POUND.format(
155                    year=self.current_year))
156            f.write('\n')
157            f.write(
158                ANDROID_MK_TEMPLATE.format(
159                    test_name=self.test_name,
160                    config_src_dir=self.test_dir[len(vts_dir) + 1:]))
161
162        path = self.test_dir
163        while not path == vts_dir:
164            target = os.path.join(path, ANDROID_MK_FILE_NAME)
165            if not os.path.exists(target):
166                print 'Creating %s' % target
167                with open(target, 'w') as f:
168                    f.write(
169                        LICENSE_STATEMENT_POUND.format(
170                            year=self.current_year))
171                    f.write(ANDROID_MK_CALL_SUB)
172            path = os.path.dirname(path)
173
174    def CreateAndroidTestXml(self):
175        '''Create AndroidTest.xml'''
176        target = os.path.join(self.test_dir, ANDROID_TEST_XML_FILE_NAME)
177        with open(target, 'w') as f:
178            print 'Creating %s' % target
179            f.write(XML_HEADER)
180            f.write(
181                LICENSE_STATEMENT_XML.format(year=self.current_year))
182            f.write(
183                ANDROID_TEST_XML_TEMPLATE.format(
184                    test_name=self.test_name,
185                    test_type=self.test_type,
186                    test_path_under_vts=self.test_dir[len(
187                        os.path.join(self.build_top, VTS_PATH)) + 1:],
188                    test_case_file_without_extension=self.test_name))
189
190    def CreateTestCasePy(self):
191        '''Create <test_case_name>.py'''
192        target = os.path.join(self.test_dir, '%s.py' % self.test_name)
193        with open(target, 'w') as f:
194            print 'Creating %s' % target
195            f.write(PY_HEADER)
196            f.write(
197                LICENSE_STATEMENT_POUND.format(
198                    year=self.current_year))
199            f.write('\n')
200            f.write(
201                TEST_CASE_PY_TEMPLATE.format(
202                    test_name=self.test_name))
203
204
205def main():
206    parser = argparse.ArgumentParser(description='Initiate a test case.')
207    parser.add_argument(
208        '--name',
209        dest='test_name',
210        required=True,
211        help='Test case name in UpperCamel. Example: VtsKernelLtp')
212    parser.add_argument(
213        '--dir',
214        dest='test_dir',
215        required=True,
216        help='Test case relative directory under test/vts/testcses.')
217    parser.add_argument(
218        '--type',
219        dest='test_type',
220        required=False,
221        help='Test type, such as HidlHalTest, HostDrivenTest, etc.')
222
223    args = parser.parse_args()
224    test_case_creater = TestCaseCreator(args.test_name, args.test_dir,
225                                        args.test_type)
226    test_case_creater.InitTestCaseDir()
227
228
229LICENSE_STATEMENT_POUND = '''#
230# Copyright (C) {year} The Android Open Source Project
231#
232# Licensed under the Apache License, Version 2.0 (the "License");
233# you may not use this file except in compliance with the License.
234# You may obtain a copy of the License at
235#
236#      http://www.apache.org/licenses/LICENSE-2.0
237#
238# Unless required by applicable law or agreed to in writing, software
239# distributed under the License is distributed on an "AS IS" BASIS,
240# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
241# See the License for the specific language governing permissions and
242# limitations under the License.
243#
244'''
245
246LICENSE_STATEMENT_XML = '''<!-- Copyright (C) {year} The Android Open Source Project
247
248     Licensed under the Apache License, Version 2.0 (the "License");
249     you may not use this file except in compliance with the License.
250     You may obtain a copy of the License at
251
252          http://www.apache.org/licenses/LICENSE-2.0
253
254     Unless required by applicable law or agreed to in writing, software
255     distributed under the License is distributed on an "AS IS" BASIS,
256     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
257     See the License for the specific language governing permissions and
258     limitations under the License.
259-->
260'''
261
262ANDROID_MK_TEMPLATE = '''LOCAL_PATH := $(call my-dir)
263
264include $(call all-subdir-makefiles)
265
266include $(CLEAR_VARS)
267
268LOCAL_MODULE := {test_name}
269VTS_CONFIG_SRC_DIR := {config_src_dir}
270include test/vts/tools/build/Android.host_config.mk
271'''
272
273ANDROID_MK_CALL_SUB = '''LOCAL_PATH := $(call my-dir)
274
275include $(call all-subdir-makefiles)
276'''
277
278XML_HEADER = '''<?xml version="1.0" encoding="utf-8"?>
279'''
280
281ANDROID_TEST_XML_TEMPLATE = '''<configuration description="Config for VTS {test_name} test cases">
282    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
283        <option name="push-group" value="{test_type}.push" />
284    </target_preparer>
285    <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
286    </target_preparer>
287    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
288        <option name="test-module-name" value="{test_name}" />
289        <option name="test-case-path" value="vts/{test_path_under_vts}/{test_case_file_without_extension}" />
290    </test>
291</configuration>
292'''
293
294PY_HEADER = '''#!/usr/bin/env python
295'''
296
297TEST_CASE_PY_TEMPLATE = '''import logging
298
299from vts.runners.host import asserts
300from vts.runners.host import base_test
301from vts.runners.host import const
302from vts.runners.host import test_runner
303from vts.utils.python.controllers import android_device
304
305
306class {test_name}(base_test.BaseTestClass):
307    """Two hello world test cases which use the shell driver."""
308
309    def setUpClass(self):
310        self.dut = self.registerController(android_device)[0]
311
312    def testEcho1(self):
313        """A simple testcase which sends a command."""
314        self.dut.shell.InvokeTerminal("my_shell1")  # creates a remote shell instance.
315        results = self.dut.shell.my_shell1.Execute("echo hello_world")  # runs a shell command.
316        logging.info(str(results[const.STDOUT]))  # prints the stdout
317        asserts.assertEqual(results[const.STDOUT][0].strip(), "hello_world")  # checks the stdout
318        asserts.assertEqual(results[const.EXIT_CODE][0], 0)  # checks the exit code
319
320    def testEcho2(self):
321        """A simple testcase which sends two commands."""
322        self.dut.shell.InvokeTerminal("my_shell2")
323        my_shell = getattr(self.dut.shell, "my_shell2")
324        results = my_shell.Execute(["echo hello", "echo world"])
325        logging.info(str(results[const.STDOUT]))
326        asserts.assertEqual(len(results[const.STDOUT]), 2)  # check the number of processed commands
327        asserts.assertEqual(results[const.STDOUT][0].strip(), "hello")
328        asserts.assertEqual(results[const.STDOUT][1].strip(), "world")
329        asserts.assertEqual(results[const.EXIT_CODE][0], 0)
330        asserts.assertEqual(results[const.EXIT_CODE][1], 0)
331
332
333if __name__ == "__main__":
334    test_runner.main()
335'''
336
337if __name__ == '__main__':
338    main()
339