• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4"""
5Copyright (c) 2021 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18Description: Use ark to execute ts/js files
19"""
20
21import os
22import sys
23import re
24import glob
25import argparse
26import subprocess
27import signal
28import time
29import json
30
31DEFAULT_TIMEOUT = 300
32DEFAULT_PGO_THRESHOLD = 10
33TARGET_PLATFORM = ['x64', 'arm64']
34PRODUCT_LIST = ['hispark_taurus', 'rk3568', 'baltimore']
35TARGET_PRODUCT_MAP = {'x64': 0, 'arm64': 1}
36
37def parse_args():
38    parser = argparse.ArgumentParser()
39    parser.add_argument('name', metavar='file|path', type=str, help='test case name: file or path')
40    parser.add_argument('-a', '--all', action='store_true', help='run all test cases on path')
41    parser.add_argument('-p', '--product', metavar='name',
42        help='product name, default is hispark_taurus on x64, rk3568 on arm64')
43    parser.add_argument('-t', '--tool', metavar='opt',
44        help='run tool supported opt: aot, int(c interpreter tool), asmint(asm interpreter tool)')
45    parser.add_argument('-s', '--step', metavar='opt',
46        help='run step supported opt: abc, pack, aot, aotd, run, rund, asmint, asmintd, int, intd')
47    parser.add_argument('-d', '--debug', action='store_true', help='run on debug mode')
48    parser.add_argument('--arm64', action='store_true', help='run on arm64 platform')
49    parser.add_argument('--aot-args', metavar='args', help='pass to aot compiler args')
50    parser.add_argument('--jsvm-args', metavar='args', help='pass to jsvm args')
51    parser.add_argument('-i', '--info', action='store_true', help='add log level of info to args')
52    parser.add_argument('-c', '--clean', action='store_true', help='clean output files')
53    parser.add_argument('--npm', action='store_true', help='npm install')
54    parser.add_argument('--bt', dest='builtin', action='store_true', help='aot compile with lib_ark_builtins.d.ts')
55    parser.add_argument('--pgo', action='store_true',
56        help=f'aot compile with pgo, default threshold is {DEFAULT_PGO_THRESHOLD}')
57    parser.add_argument('--pgo-th', metavar='n', default=DEFAULT_PGO_THRESHOLD, type=int,
58        help=f'pgo hotness threshold, default is {DEFAULT_PGO_THRESHOLD}')
59    parser.add_argument('--timeout', metavar='n', default=DEFAULT_TIMEOUT, type=int,
60        help=f'specify seconds of test timeout, default is {DEFAULT_TIMEOUT}')
61    parser.add_argument('-e', '--env', action='store_true', help='print LD_LIBRARY_PATH')
62    arguments = parser.parse_args()
63    return arguments
64
65def run_command(cmd, timeout=DEFAULT_TIMEOUT):
66    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
67    code_format = 'UTF-8'
68    try:
69        (msg, errs) = proc.communicate(timeout=timeout)
70        ret_code = proc.poll()
71        if errs:
72            ret_code = 2
73    except subprocess.TimeoutExpired:
74        proc.kill()
75        proc.terminate()
76        os.kill(proc.pid, signal.SIGTERM)
77        return (1, '', f'exec command timeout {timeout}s')
78    return (ret_code, msg.decode(code_format), errs.decode(code_format))
79
80def match_list_name(list, name):
81    for str in list:
82        found = str.find(name)
83        if (found == 0):
84            return str
85    return ''
86
87class ArkTest():
88    def __init__(self, args):
89        self.args = args
90        self.self_dir = os.path.abspath(sys.argv[0])
91        self.hap_abc = 'ets/modules.abc'
92        self.place_dir = 'arkcompiler/ets_runtime/test'
93        if self.self_dir.find(self.place_dir) < 0:
94            print(f'pls place this script at: {self.place_dir}')
95            sys.exit(1)
96
97        self.ohdir = os.path.abspath(f'{self.self_dir}/../../../..')
98        self.product = PRODUCT_LIST[TARGET_PRODUCT_MAP['x64']]
99        self.builtin = ''
100        if args.builtin:
101            self.builtin = f'{self.ohdir}/arkcompiler/ets_runtime/ecmascript/ts_types/lib_ark_builtins.d'
102        self.arm64 = False
103        if args.step == 'hap':
104            self.arm64 = True
105        if args.arm64:
106            self.product = PRODUCT_LIST[TARGET_PRODUCT_MAP['arm64']]
107            self.arm64 = True
108        if args.product:
109            self.product = match_list_name(PRODUCT_LIST, args.product)
110        self.step = 'all'
111        if args.step:
112            self.step = args.step
113        if args.clean:
114            self.step = 'clean'
115        self.expect = 'expect_output.txt'
116        self.types = {'all': ['.ts', '.js'],
117                      'abc': ['.ts', '.js'],
118                      'pack': ['.an'],
119                      'aot': ['.abc'],
120                      'aotd': ['.abc'],
121                      'run': ['.abc'],
122                      'rund': ['.abc'],
123                      'asmint': ['.abc'],
124                      'asmintd': ['.abc'],
125                      'int': ['.abc'],
126                      'intd': ['.abc'],
127                      'clean': ['.abc']}
128
129        product_dir = f'{self.ohdir}/out/{self.product}'
130        libs_dir_x64_release = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib:'
131                                f'{product_dir}/clang_x64/arkcompiler/ets_runtime:'
132                                f'{product_dir}/clang_x64/thirdparty/icu')
133        libs_dir_x64_debug = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib:'
134                              f'{product_dir}/clang_x64/exe.unstripped/clang_x64/arkcompiler/ets_runtime:'
135                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/arkcompiler/ets_runtime:'
136                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/test/test:'
137                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/thirdparty/icu')
138        libs_dir_arm64_release = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++/:'
139                                  f'{product_dir}/arkcompiler/ets_runtime/:'
140                                  f'{product_dir}/utils/utils_base/:'
141                                  f'{product_dir}/thirdparty/icu:'
142                                  f'{product_dir}/common/dsoftbus/:'
143                                  f'{product_dir}/commonlibrary/c_utils:'
144                                  f'{product_dir}/systemabilitymgr/samgr:'
145                                  f'{product_dir}/hiviewdfx/hisysevent_native:'
146                                  f'{product_dir}/common/common:'
147                                  f'{product_dir}/securec/thirdparty_bounds_checking_function:'
148                                  f'{product_dir}/hiviewdfx/faultloggerd:'
149                                  f'{product_dir}/thirdparty/bounds_checking_function:'
150                                  f'{product_dir}/hiviewdfx/hilog_native:'
151                                  f'{product_dir}/startup/init:'
152                                  f'{product_dir}/thirdparty/cjson:'
153                                  f'{product_dir}/lib.unstripped/common/dsoftbus:'
154                                  f'{product_dir}/security/selinux:'
155                                  f'{product_dir}/hiviewdfx/hitrace_native/:'
156                                  f'{product_dir}/communication/ipc/:'
157                                  f'{product_dir}/distributedschedule/samgr_standard:'
158                                  f'{product_dir}/security/access_token:'
159                                  f'{product_dir}/communication/dsoftbus:'
160                                  f'{product_dir}/startup/startup_l2/:'
161                                  f'{product_dir}/security/huks/:'
162                                  f'{product_dir}/clang_x64/thirdparty/icu/:'
163                                  f'{product_dir}/clang_x64/arkcompiler/ets_runtime')
164        libs_dir_arm64_debug = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++/:'
165                                f'{product_dir}/lib.unstripped/arkcompiler/ets_runtime/:'
166                                f'{product_dir}/utils/utils_base/:'
167                                f'{product_dir}/thirdparty/icu:'
168                                f'{product_dir}/common/dsoftbus/:'
169                                f'{product_dir}/commonlibrary/c_utils:'
170                                f'{product_dir}/systemabilitymgr/samgr:'
171                                f'{product_dir}/hiviewdfx/hisysevent_native:'
172                                f'{product_dir}/common/common:'
173                                f'{product_dir}/securec/thirdparty_bounds_checking_function:'
174                                f'{product_dir}/hiviewdfx/faultloggerd:'
175                                f'{product_dir}/thirdparty/bounds_checking_function:'
176                                f'{product_dir}/hiviewdfx/hilog_native:'
177                                f'{product_dir}/startup/init:'
178                                f'{product_dir}/thirdparty/cjson:'
179                                f'{product_dir}/security/selinux:'
180                                f'{product_dir}/hiviewdfx/hitrace_native/:'
181                                f'{product_dir}/communication/ipc/:'
182                                f'{product_dir}/distributedschedule/samgr_standard:'
183                                f'{product_dir}/security/access_token:'
184                                f'{product_dir}/communication/dsoftbus:'
185                                f'{product_dir}/startup/startup_l2/:'
186                                f'{product_dir}/security/huks/:'
187                                f'{product_dir}/clang_x64/thirdparty/icu/:'
188                                f'{product_dir}/clang_x64/arkcompiler/ets_runtime')
189        libs_dir = [[libs_dir_x64_release, libs_dir_x64_debug], [libs_dir_arm64_release, libs_dir_arm64_debug]]
190        bins_dir = [['clang_x64/arkcompiler', 'clang_x64/exe.unstripped/clang_x64/arkcompiler'],
191                    ['arkcompiler', 'exe.unstripped/arkcompiler']]
192        icu_arg = f'--icu-data-path={self.ohdir}/third_party/icu/ohos_icu4j/data'
193        self.libs_dir = libs_dir[self.arm64][args.debug]
194        self.compiler = f'{product_dir}/{bins_dir[0][args.debug]}/ets_runtime/ark_aot_compiler'
195        self.jsvm = f'{product_dir}/{bins_dir[self.arm64][args.debug]}/ets_runtime/ark_js_vm'
196        self.ts2abc = f'{product_dir}/clang_x64/arkcompiler/ets_frontend/build/src/index.js'
197        self.builtin
198        self.aot_args = ''
199        self.jsvm_args = icu_arg
200        if self.builtin:
201            self.aot_args = f'{self.aot_args} --builtins-dts={self.builtin}.abc'
202        self.pgo = False
203        if args.pgo:
204            self.pgo = True
205            self.aot_args = (f'{self.aot_args} --enable-pgo-profiler=true --pgo-hotness-threshold={args.pgo_th}'
206                             f' --pgo-profiler-path=pgo_file_name.ap')
207        if args.aot_args:
208            self.aot_args = f'{self.aot_args} {args.aot_args}'
209        if args.jsvm_args:
210            self.jsvm_args = f'{self.jsvm_args} {args.jsvm_args}'
211        if args.info:
212            self.aot_args = f'{self.aot_args} --log-level=info'
213            self.jsvm_args = f'{self.jsvm_args} --log-level=info'
214        self.runner = ''
215        self.runnerd = 'gdb --args'
216        if self.arm64:
217            if self.step[:3] != 'aot':
218                self.runner = 'qemu-aarch64'
219                self.runnerd = 'qemu-aarch64 -cpu max,sve=off -g 123456'
220            self.aot_args = f'{self.aot_args} --target-triple=aarch64-unknown-linux-gnu'
221        self.test_count = 0
222        self.fail_cases = []
223        os.environ['LD_LIBRARY_PATH'] = self.libs_dir
224        if args.env:
225            print(f'export LD_LIBRARY_PATH={self.libs_dir}')
226            sys.exit(0)
227        if args.npm:
228            index_dir = os.path.dirname(self.ts2abc)
229            os.system(f'cd {index_dir}/.. && npm install')
230            sys.exit(0)
231
232    def run_cmd(self, cmd):
233        print(cmd)
234        ret = run_command(cmd, self.args.timeout)
235        if ret[0]:
236            print(ret[2])
237        return ret
238
239    @staticmethod
240    def get_module_name(hap_dir):
241        with open(f'{hap_dir}/module.json') as f:
242            data = json.load(f)
243        if len(data):
244            return data['module']['name']
245        else:
246            return 'entry'
247
248    def run_test(self, file):
249        self.test_count += 1
250        basename = os.path.basename(f'{file}')
251        type = os.path.splitext(basename)[-1]
252        name = os.path.splitext(basename)[0]
253        dir = os.path.dirname(file)
254        out_case_dir = f'{dir}'
255        hap_dir = 'null'
256        hap_name = 'null'
257        module_name = 'null'
258        if self.step == 'hap' or self.step == 'pack':
259            hap_dir = os.path.abspath(f'{out_case_dir}/..')
260            hap_name = os.path.basename(hap_dir)
261            module_name = self.get_module_name(hap_dir)
262        abc_file = f'{os.path.splitext(file)[0]}.abc'
263        if self.pgo:
264            pgo_file = f'{hap_dir}/ap/{module_name}'
265            self.aot_args = self.aot_args.replace('pgo_file_name', pgo_file)
266        cmd_map = {
267            'abc': f'node --expose-gc {self.ts2abc} {file} --merge-abc',
268            'pack': [f'mkdir -p {out_case_dir}/../an/arm64-v8a',
269                     f'mv {out_case_dir}/{name}.an {hap_dir}/an/arm64-v8a/{module_name}.an',
270                     f'mv {out_case_dir}/{name}.ai {hap_dir}/an/arm64-v8a/{module_name}.ai',
271                     f'cd {out_case_dir}/.. && rm -f ../{hap_name}.hap && zip -r -q ../{hap_name}.hap *',
272                     f'mv {hap_dir}/an/arm64-v8a/{module_name}.an {out_case_dir}/{name}.an',
273                     f'mv {hap_dir}/an/arm64-v8a/{module_name}.ai {out_case_dir}/{name}.ai',
274                     f'rm -rf {hap_dir}/an'],
275            'aot': f'{self.compiler} {self.aot_args} --aot-file={out_case_dir}/{name} {abc_file}',
276            'aotd': f'{self.runnerd} {self.compiler} {self.aot_args} --aot-file={out_case_dir}/{name} {abc_file}',
277            'run': f'{self.runner} {self.jsvm} {self.jsvm_args} --aot-file={out_case_dir}/{name} --entry-point={name} {abc_file}',
278            'rund': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --aot-file={out_case_dir}/{name} --entry-point={name} {abc_file}',
279            'asmint': f'{self.runner} {self.jsvm} {self.jsvm_args} --entry-point={name} {abc_file}',
280            'asmintd': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --entry-point={name} {abc_file}',
281            'int': f'{self.runner} {self.jsvm} {self.jsvm_args} --asm-interpreter=0 --entry-point={name} {abc_file}',
282            'intd': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --asm-interpreter=0 --entry-point={name} {abc_file}',
283            'clean': f'rm -f {out_case_dir}/{name}.abc {out_case_dir}/{name}.an {out_case_dir}/{name}.ai',
284            'cleanhap': f'rm -rf {hap_dir}/an {out_case_dir}/{name}.an {out_case_dir}/{name}.ai'}
285        if self.builtin:
286            cmd = f'node --expose-gc {self.ts2abc} {self.builtin}.ts -m --merge-abc -q -b'
287            print(cmd)
288            os.system(cmd)
289        if self.step == 'hap':
290            self.step = 'aot'
291            perf_start = time.perf_counter()
292            cmd = cmd_map[self.step]
293            print(cmd)
294            os.system(cmd)
295            perf_end = time.perf_counter()
296            abc_size = os.path.getsize(file) / 1024
297            an_size = os.path.getsize(f'{out_case_dir}/{name}.an') / 1024
298            print(f'test: {file}  abc_size: {abc_size: .1f}KB  an_size: {an_size:.1f}KB  '
299                  f'expand: {an_size / abc_size: .1f}  time: {perf_end - perf_start: .1f}s')
300            self.step = 'pack'
301        if self.step == 'pack':
302            for cmd in cmd_map[self.step]:
303                print(cmd)
304                os.system(cmd)
305            print(f'packed hap: {hap_name}.hap')
306            return
307        if self.step == 'clean':
308            if os.path.isfile(f'{hap_dir}/{self.hap_abc}'):
309                self.step = 'cleanhap'
310        if self.step != 'all':
311            # gdb should use the os.system
312            cmd = cmd_map[self.step]
313            print(cmd)
314            if self.arm64 and self.step[-1:] == 'd' and self.step[:3] != 'aot':
315                print(f'gdb-client start:   gdb-multiarch {self.jsvm}')
316                print(f'gdb-server connect: target remote:123456')
317            os.system(cmd)
318            return
319        ret = self.run_cmd(cmd_map['abc'])
320        if ret[0]:
321            self.judge_test(file, ret)
322            return
323        if (not self.args.tool) or (self.args.tool == 'aot'):
324            ret = self.run_cmd(cmd_map['aot'])
325            if ret[0] and ret[2].find('aot compile success') < 0:
326                self.judge_test(file, ret)
327                return
328            ret = self.run_cmd(cmd_map['run'])
329        else:
330            ret = self.run_cmd(cmd_map[self.args.tool])
331        self.judge_test(file, ret)
332
333    def judge_test(self, file, out):
334        if out[0]:
335            self.fail_cases.append(file)
336            print_fail(f'FAIL: {file}')
337            return
338        expect_file = f'{os.path.dirname(file)}/{self.expect}'
339        if os.path.exists(expect_file):
340            with open(expect_file, mode='r') as infile:
341                expect = ''.join(infile.readlines()[13:])
342            if out[1] != expect:
343                self.fail_cases.append(file)
344                print(f'expect: [{expect}]\nbut got: [{out[1]}]')
345                print_fail(f'FAIL: {file}')
346            else:
347                print_pass(f'PASS: {file}')
348        else:
349            print_pass(f'PASS: {file}')
350            print(out[1])
351
352    def report_test(self):
353        fail_count = len(self.fail_cases)
354        print(f'Ran tests: {self.test_count}')
355        print(f'Ran failed: {fail_count}')
356        if fail_count == 0:
357            print_pass('================================== All tests Run PASSED!')
358            return
359        print_fail('==================================')
360        for case in self.fail_cases:
361            print(case)
362        print_fail('==================================')
363
364    def find_file(self, dir, postfix_list):
365        result = []
366        for root, lists, files in os.walk(dir):
367            for file in files:
368                for postfix in postfix_list:
369                    path = os.path.join(root, file)
370                    found = path.find(postfix)
371                    if found == len(path) - len(postfix):
372                        result.append(path)
373        if os.path.isfile(dir):
374            for postfix in postfix_list:
375                found = dir.find(postfix)
376                if found == len(dir) - len(postfix):
377                    result.append(dir)
378                    break
379        return result
380
381    def test_hap(self):
382        if self.step != 'all':
383            return 1
384        files = self.find_file(self.args.name, [self.hap_abc, '.hap'])
385        if len(files):
386            self.step = 'hap'
387            file = files[0]
388            type = os.path.splitext(file)[-1]
389            if type == '.hap':
390                hap_dir = f'{os.path.splitext(file)[0]}.aot'
391                os.system(f'mkdir -p {hap_dir} && unzip -o -q {file} -d {hap_dir}')
392                file = f'{hap_dir}/{self.hap_abc}'
393            self.run_test(file)
394            return 0
395        return 1
396
397    def test(self):
398        # run single test by name
399        files = []
400        if self.step not in self.types:
401            print(f'not supported step: {self.step}')
402            return 1
403        if not self.args.all:
404            files = self.find_file(self.args.name, self.types[self.step])
405            if len(files):
406                self.run_test(files[0])
407            elif self.test_hap():
408                print(f'input path no test case: {self.args.name}')
409                return 1
410            return 0
411
412        # run all test in path
413        if not os.path.isdir(self.args.name):
414            print(f'input path not exists or is file: {self.args.name}')
415            return 1
416        files = self.find_file(self.args.name, self.types[self.step])
417        for test in files:
418            self.run_test(test)
419
420        if len(files) == 0:
421            self.test_hap()
422
423        if self.step == 'clean':
424            print('clean output files finished')
425            return 0
426
427        if self.test_count == 0:
428            print(f'input path no test case: {self.args.name}')
429            return 1
430
431        # output report
432        self.report_test()
433        return 0
434
435def print_pass(str):
436    print(f'\033[32;2m{str}\033[0m')
437    sys.stdout.flush()
438
439def print_fail(str):
440    print(f'\033[31;2m{str}\033[0m')
441    sys.stdout.flush()
442
443def main():
444    args = parse_args()
445    arktest = ArkTest(args)
446    return arktest.test()
447
448if __name__ == '__main__':
449    sys.exit(main())
450