• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2018 - 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"""Functional test for aidegen project files."""
18
19from __future__ import absolute_import
20
21import argparse
22import itertools
23import json
24import os
25import sys
26import xml.etree.ElementTree
27import xml.parsers.expat
28
29import aidegen.lib.errors
30
31from aidegen import aidegen_main
32from aidegen.lib.common_util import get_related_paths
33from aidegen.lib.common_util import time_logged
34from atest import constants
35from atest import module_info
36from atest import atest_utils
37
38_ANDROID_ROOT_PATH = os.environ.get(constants.ANDROID_BUILD_TOP)
39_ROOT_DIR = os.path.join(_ANDROID_ROOT_PATH,
40                         'tools/asuite/aidegen_functional_test')
41_TEST_DATA_PATH = os.path.join(_ROOT_DIR, 'test_data')
42_ANDROID_SINGLE_PROJECT_JSON = os.path.join(_TEST_DATA_PATH,
43                                            'single_module.json')
44_VERIFY_COMMANDS_JSON = os.path.join(_TEST_DATA_PATH, 'verify_commands.json')
45_PRODUCT_DIR = '$PROJECT_DIR$'
46_ANDROID_COMMON = 'android_common'
47_LINUX_GLIBC_COMMON = 'linux_glibc_common'
48_SRCS = 'srcs'
49_JARS = 'jars'
50_URL = 'url'
51_TEST_ERROR = ('AIDEGen functional test error: %s-%s is different.')
52_MSG_NOT_IN_PROJECT_FILE = ('%s is expected, but not found in the created '
53                            'project file: %s')
54_MSG_NOT_IN_SAMPLE_DATA = ('%s is unexpected, but found in the created project '
55                           'file: %s')
56_TEST_IML_DICT = {
57    'SystemUI': ['SystemUI.iml', 'dependencies-SystemUI.iml'],
58    'tradefed': ['core.iml', 'dependencies-core.iml']
59}
60_ALL_PASS = 'All tests passed!'
61
62
63def _parse_args(args):
64    """Parse command line arguments.
65
66    Args:
67        args: A list of arguments.
68
69    Returns:
70        An argparse.Namespace class instance holding parsed args.
71    """
72    parser = argparse.ArgumentParser(
73        description=__doc__,
74        formatter_class=argparse.RawDescriptionHelpFormatter,
75        usage='aidegen_functional_test [-c | -v]')
76    group = parser.add_mutually_exclusive_group()
77    parser.required = False
78    group.add_argument(
79        '-c',
80        '--create-sample',
81        action='store_true',
82        dest='create_sample',
83        help=('Create aidegen project files and write data to sample json file '
84              'for aidegen_functional_test to compare.'))
85    group.add_argument(
86        '-v',
87        '--verify',
88        action='store_true',
89        dest='verify_aidegen',
90        help='Verify various use cases of executing aidegen.')
91    return parser.parse_args(args)
92
93
94def _import_project_file_xml_etree(filename):
95    """Import iml project file and load data into a dictionary.
96
97    Args:
98        filename: The input project file name.
99    """
100    data = {}
101    try:
102        tree = xml.etree.ElementTree.parse(filename)
103        data[_SRCS] = []
104        root = tree.getroot()
105        for element in root.iter('sourceFolder'):
106            src = element.get(_URL).replace(_ANDROID_ROOT_PATH, _PRODUCT_DIR)
107            data[_SRCS].append(src)
108        data[_JARS] = []
109        for element in root.iter('root'):
110            jar = element.get(_URL).replace(_ANDROID_ROOT_PATH, _PRODUCT_DIR)
111            data[_JARS].append(jar)
112    except (EnvironmentError, ValueError, LookupError,
113            xml.parsers.expat.ExpatError) as err:
114        print("{0}: import error: {1}".format(os.path.basename(filename), err))
115        raise
116    return data
117
118
119def _generate_sample_json():
120    """Generate sample iml data and write into a json file."""
121    atest_module_info = module_info.ModuleInfo()
122    data = {}
123    for target, filelist in _TEST_IML_DICT.items():
124        aidegen_main.main([target, '-n'])
125        _, abs_path = get_related_paths(atest_module_info, target)
126        for filename in filelist:
127            real_iml_file = os.path.join(abs_path, filename)
128            item_name = os.path.basename(real_iml_file)
129            data[item_name] = _import_project_file_xml_etree(real_iml_file)
130    return data
131
132
133def _create_sample_json_file():
134    """Write samples' iml data into a json file.
135
136    linked_function: _generate_sample_json()
137    """
138    data = _generate_sample_json()
139    with open(_ANDROID_SINGLE_PROJECT_JSON, 'w') as outfile:
140        json.dump(data, outfile, indent=4, sort_keys=False)
141
142
143def test_some_sample_iml():
144    """Compare sample iml data to assure project iml file contents is right."""
145    test_successful = True
146    with open(_ANDROID_SINGLE_PROJECT_JSON, 'r') as outfile:
147        data_sample = json.load(outfile)
148    data_real = _generate_sample_json()
149    for name in data_real:
150        for item in [_SRCS, _JARS]:
151            s_items = data_sample[name][item]
152            r_items = data_real[name][item]
153            if set(s_items) != set(r_items):
154                diff_iter = _compare_content(name, item, s_items, r_items)
155                if diff_iter:
156                    print('\n%s\n%s' % (atest_utils.colorize(
157                        'Test error...', constants.RED), _TEST_ERROR %
158                                        (name, item)))
159                    print('%s %s contents are different:' % (name, item))
160                    for diff in diff_iter:
161                        print(diff)
162                    test_successful = False
163    if test_successful:
164        print(atest_utils.colorize(_ALL_PASS, constants.GREEN))
165
166
167def _compare_content(module_name, item_type, s_items, r_items):
168    """Compare src or jar files' data of two dictionaries.
169
170    Args:
171        module_name: the test module name.
172        item_type: the type is src or jar.
173        s_items: sample jars' items.
174        r_items: real jars' items.
175
176    Returns:
177        An iterator of not equal sentences after comparison.
178    """
179    if item_type == _SRCS:
180        cmp_iter1 = _compare_srcs_content(module_name, s_items, r_items,
181                                          _MSG_NOT_IN_PROJECT_FILE)
182        cmp_iter2 = _compare_srcs_content(module_name, r_items, s_items,
183                                          _MSG_NOT_IN_SAMPLE_DATA)
184    else:
185        cmp_iter1 = _compare_jars_content(module_name, s_items, r_items,
186                                          _MSG_NOT_IN_PROJECT_FILE)
187        cmp_iter2 = _compare_jars_content(module_name, r_items, s_items,
188                                          _MSG_NOT_IN_SAMPLE_DATA)
189    return itertools.chain(cmp_iter1, cmp_iter2)
190
191
192def _compare_srcs_content(module_name, s_items, r_items, msg):
193    """Compare src or jar files' data of two dictionaries.
194
195    Args:
196        module_name: the test module name.
197        s_items: sample jars' items.
198        r_items: real jars' items.
199        msg: the message will be written into log file.
200
201    Returns:
202        An iterator of not equal sentences after comparison.
203    """
204    for sample in s_items:
205        if not sample in r_items:
206            yield msg % (sample, module_name)
207
208
209def _compare_jars_content(module_name, s_items, r_items, msg):
210    """Compare src or jar files' data of two dictionaries.
211
212    Args:
213        module_name: the test module name.
214        s_items: sample jars' items.
215        r_items: real jars' items.
216        msg: the message will be written into log file.
217
218    Returns:
219        An iterator of not equal sentences after comparison.
220    """
221    for sample in s_items:
222        if not sample in r_items:
223            lnew = sample
224            if _LINUX_GLIBC_COMMON in sample:
225                lnew = sample.replace(_LINUX_GLIBC_COMMON, _ANDROID_COMMON)
226            else:
227                lnew = sample.replace(_ANDROID_COMMON, _LINUX_GLIBC_COMMON)
228            if not lnew in r_items:
229                yield msg % (sample, module_name)
230
231
232# pylint: disable=broad-except
233# pylint: disable=eval-used
234@time_logged
235def _verify_aidegen():
236    """Verify various use cases of executing aidegen."""
237    with open(_VERIFY_COMMANDS_JSON, 'r') as jsfile:
238        data = json.load(jsfile)
239    for use_case in data:
240        for cmd in data[use_case]:
241            try:
242                eval(cmd)
243            except (aidegen.lib.errors.ProjectOutsideAndroidRootError,
244                    aidegen.lib.errors.ProjectPathNotExistError,
245                    aidegen.lib.errors.NoModuleDefinedInModuleInfoError,
246                    aidegen.lib.errors.IDENotExistError) as err:
247                print('{} command has raise error: {}.'.format(use_case, err))
248            except Exception as exp:
249                print('{}.{} command {}.'.format(
250                    use_case, cmd,
251                    atest_utils.colorize('executes failed', constants.RED)))
252                raise Exception(
253                    'Unexpected command {} exception {}.'.format(use_case, exp))
254        print('{} command {}!'.format(
255            use_case, atest_utils.colorize('test passed', constants.GREEN)))
256    print(atest_utils.colorize(_ALL_PASS, constants.GREEN))
257
258
259def main(argv):
260    """Main entry.
261
262    Compare iml project files to the data recorded in single_module.json.
263
264    Args:
265        argv: A list of system arguments.
266    """
267    args = _parse_args(argv)
268    if args.create_sample:
269        _create_sample_json_file()
270    elif args.verify_aidegen:
271        _verify_aidegen()
272    else:
273        test_some_sample_iml()
274
275
276if __name__ == '__main__':
277    main(sys.argv[1:])
278