xref: /arkcompiler/ets_runtime/test/runtest.py (revision 4514f5e3)
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, baltimore 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), node(v8), qjs, hermes')
45    parser.add_argument('-f', '--frontend', metavar='opt',
46        help='run frontend supported opt: ts2abc (slow), es2abc (quick not released)')
47    parser.add_argument('-s', '--step', metavar='opt',
48        help='run step supported opt: abc, pack, aot, aotd, run, rund, asmint, asmintd, int, intd')
49    parser.add_argument('-d', '--debug', action='store_true', help='run on debug mode')
50    parser.add_argument('--arm64', action='store_true', help='run on arm64 platform')
51    parser.add_argument('--device', action='store_true', help='run on device')
52    parser.add_argument('--copy-path', metavar='path', help='copy bins to device')
53    parser.add_argument('-m', '--module', action='store_true', help='frontend compile with module')
54    parser.add_argument('--frontend-args', metavar='args', help='pass to frontend args')
55    parser.add_argument('--aot-args', metavar='args', help='pass to aot compiler args')
56    parser.add_argument('--jsvm-args', metavar='args', help='pass to jsvm args')
57    parser.add_argument('-i', '--info', action='store_true', help='add log level of info to args')
58    parser.add_argument('-c', '--clean', action='store_true', help='clean output files')
59    parser.add_argument('--npm', action='store_true', help='npm install')
60    parser.add_argument('--bt', dest='builtin', action='store_true', help='aot compile with lib_ark_builtins.d.ts')
61    parser.add_argument('--pgo', action='store_true',
62        help=f'aot compile with pgo, default threshold is {DEFAULT_PGO_THRESHOLD}')
63    parser.add_argument('--pgo-th', metavar='n', default=DEFAULT_PGO_THRESHOLD, type=int,
64        help=f'pgo hotness threshold, default is {DEFAULT_PGO_THRESHOLD}')
65    parser.add_argument('--sign', metavar='name',
66        help='sign level, default is system_core, other is normal, system_basic')
67    parser.add_argument('--timeout', metavar='n', default=DEFAULT_TIMEOUT, type=int,
68        help=f'specify seconds of test timeout, default is {DEFAULT_TIMEOUT}')
69    parser.add_argument('-e', '--env', action='store_true', help='print LD_LIBRARY_PATH')
70    arguments = parser.parse_args()
71    return arguments
72
73def run_and_print(cmd):
74    print(cmd)
75    os.system(cmd)
76
77def run_command(cmd, timeout=DEFAULT_TIMEOUT):
78    proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
79    code_format = 'UTF-8'
80    try:
81        (msg, errs) = proc.communicate(timeout=timeout)
82        ret_code = proc.poll()
83        if errs:
84            ret_code = 2
85    except subprocess.TimeoutExpired:
86        proc.kill()
87        proc.terminate()
88        os.kill(proc.pid, signal.SIGTERM)
89        return (1, '', f'exec command timeout {timeout}s')
90    return (ret_code, msg.decode(code_format), errs.decode(code_format))
91
92def match_list_name(list, name):
93    for str in list:
94        found = str.find(name)
95        if (found == 0):
96            return str
97    return ''
98
99def get_module_name(hap_dir):
100    with open(f'{hap_dir}/module.json') as f:
101        data = json.load(f)
102    if len(data):
103        return data['module']['name']
104    else:
105        return 'entry'
106
107def get_bundle_name(hap_dir):
108    with open(f'{hap_dir}/module.json') as f:
109        data = json.load(f)
110    if len(data):
111        return data['app']['bundleName']
112    else:
113        return 'entry'
114
115class ArkTest():
116    def __init__(self, args):
117        self.args = args
118        self.self_dir = os.path.abspath(sys.argv[0])
119        self.hap_abc = 'ets/modules.abc'
120        self.place_dir = 'arkcompiler/ets_runtime/test'
121        if not args.device and self.self_dir.find(self.place_dir) < 0:
122            print(f'pls place this script at: {self.place_dir}')
123            sys.exit(1)
124
125        self.ohdir = os.path.abspath(f'{self.self_dir}/../../../..')
126        self.product = PRODUCT_LIST[TARGET_PRODUCT_MAP['x64']]
127        self.builtin = ''
128        self.arm64 = False
129        if args.step == 'hap':
130            self.arm64 = True
131        if args.arm64:
132            self.product = PRODUCT_LIST[TARGET_PRODUCT_MAP['arm64']]
133            self.arm64 = True
134        if args.product:
135            self.product = match_list_name(PRODUCT_LIST, args.product)
136        self.step = 'all'
137        if args.step:
138            self.step = args.step
139        if args.clean:
140            self.step = 'clean'
141        self.expect = 'expect_output.txt'
142        search_type_list = ['.ts', '.js', '.abc']
143        self.types = {'all': ['.ts', '.js'],
144                      'abc': ['.ts', '.js'],
145                      'pack': ['.an'],
146                      'aot': search_type_list,
147                      'aotd': search_type_list,
148                      'run': search_type_list,
149                      'rund': search_type_list,
150                      'asmint': search_type_list,
151                      'asmintd': search_type_list,
152                      'int': search_type_list,
153                      'intd': search_type_list,
154                      'clean': search_type_list}
155
156        product_dir = f'{self.ohdir}/out/{self.product}'
157        libs_dir_x64_release = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib:'
158                                f'{product_dir}/clang_x64/arkcompiler/ets_runtime:'
159                                f'{product_dir}/clang_x64/thirdparty/icu:'
160                                f'{product_dir}/clang_x64/thirdparty/zlib')
161        libs_dir_x64_debug = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib:'
162                              f'{product_dir}/clang_x64/exe.unstripped/clang_x64/arkcompiler/ets_runtime:'
163                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/arkcompiler/ets_runtime:'
164                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/test/test:'
165                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/thirdparty/icu:'
166                              f'{product_dir}/clang_x64/lib.unstripped/clang_x64/thirdparty/zlib')
167        libs_dir_arm64_release = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++/:'
168                                  f'{product_dir}/arkcompiler/ets_runtime/:'
169                                  f'{product_dir}/utils/utils_base/:'
170                                  f'{product_dir}/thirdparty/icu:'
171                                  f'{product_dir}/thirdparty/zlib:'
172                                  f'{product_dir}/common/dsoftbus/:'
173                                  f'{product_dir}/commonlibrary/c_utils:'
174                                  f'{product_dir}/systemabilitymgr/samgr:'
175                                  f'{product_dir}/hiviewdfx/hisysevent_native:'
176                                  f'{product_dir}/common/common:'
177                                  f'{product_dir}/securec/thirdparty_bounds_checking_function:'
178                                  f'{product_dir}/hiviewdfx/faultloggerd:'
179                                  f'{product_dir}/thirdparty/bounds_checking_function:'
180                                  f'{product_dir}/hiviewdfx/hilog_native:'
181                                  f'{product_dir}/startup/init:'
182                                  f'{product_dir}/thirdparty/cjson:'
183                                  f'{product_dir}/lib.unstripped/common/dsoftbus:'
184                                  f'{product_dir}/security/selinux:'
185                                  f'{product_dir}/hiviewdfx/hitrace_native/:'
186                                  f'{product_dir}/communication/ipc/:'
187                                  f'{product_dir}/distributedschedule/samgr_standard:'
188                                  f'{product_dir}/security/access_token:'
189                                  f'{product_dir}/communication/dsoftbus:'
190                                  f'{product_dir}/startup/startup_l2/:'
191                                  f'{product_dir}/security/huks/:'
192                                  f'{product_dir}/clang_x64/thirdparty/icu:'
193                                  f'{product_dir}/clang_x64/thirdparty/zlib:'
194                                  f'{product_dir}/clang_x64/arkcompiler/ets_runtime')
195        libs_dir_arm64_debug = (f'{self.ohdir}/prebuilts/clang/ohos/linux-x86_64/llvm/lib/aarch64-linux-ohos/c++/:'
196                                f'{product_dir}/lib.unstripped/arkcompiler/ets_runtime/:'
197                                f'{product_dir}/utils/utils_base/:'
198                                f'{product_dir}/thirdparty/icu:'
199                                f'{product_dir}/thirdparty/zlib:'
200                                f'{product_dir}/common/dsoftbus/:'
201                                f'{product_dir}/commonlibrary/c_utils:'
202                                f'{product_dir}/systemabilitymgr/samgr:'
203                                f'{product_dir}/hiviewdfx/hisysevent_native:'
204                                f'{product_dir}/common/common:'
205                                f'{product_dir}/securec/thirdparty_bounds_checking_function:'
206                                f'{product_dir}/hiviewdfx/faultloggerd:'
207                                f'{product_dir}/thirdparty/bounds_checking_function:'
208                                f'{product_dir}/hiviewdfx/hilog_native:'
209                                f'{product_dir}/startup/init:'
210                                f'{product_dir}/thirdparty/cjson:'
211                                f'{product_dir}/security/selinux:'
212                                f'{product_dir}/hiviewdfx/hitrace_native/:'
213                                f'{product_dir}/communication/ipc/:'
214                                f'{product_dir}/distributedschedule/samgr_standard:'
215                                f'{product_dir}/security/access_token:'
216                                f'{product_dir}/communication/dsoftbus:'
217                                f'{product_dir}/startup/startup_l2/:'
218                                f'{product_dir}/security/huks/:'
219                                f'{product_dir}/clang_x64/thirdparty/icu/:'
220                                f'{product_dir}/clang_x64/thirdparty/zlib/:'
221                                f'{product_dir}/clang_x64/arkcompiler/ets_runtime')
222        libs_dir = [[libs_dir_x64_release, libs_dir_x64_debug], [libs_dir_arm64_release, libs_dir_arm64_debug]]
223        bins_dir = [['clang_x64/arkcompiler', 'clang_x64/exe.unstripped/clang_x64/arkcompiler'],
224                    ['arkcompiler', 'exe.unstripped/arkcompiler']]
225        icu_arg = f'--icu-data-path={self.ohdir}/third_party/icu/ohos_icu4j/data'
226        self.libs_dir = libs_dir[self.arm64][args.debug]
227        self.compiler = f'{product_dir}/{bins_dir[0][args.debug]}/ets_runtime/ark_aot_compiler'
228        self.jsvm = f'{product_dir}/{bins_dir[self.arm64][args.debug]}/ets_runtime/ark_js_vm'
229        self.ts2abc = f'node --expose-gc {product_dir}/clang_x64/arkcompiler/ets_frontend/build/src/index.js'
230        self.es2abc = f'{product_dir}/clang_x64/arkcompiler/ets_frontend/es2abc'
231        self.frontend = self.ts2abc
232        if not args.frontend:
233            args.frontend = 'ts2abc'
234        if args.frontend not in ['ts2abc', 'es2abc']:
235            print(f'not supported frontend: {args.frontend}')
236            sys.exit(1)
237        if args.frontend == 'es2abc':
238            self.frontend = self.es2abc
239        abcmode = {'ts2abc': ['--merge-abc', '--merge-abc -m'],
240                   'es2abc': ['--merge-abc', '--merge-abc --module']}
241        self.abcmode = abcmode[args.frontend][args.module]
242        self.frontend_args = ''
243        self.aot_args = ''
244        self.jsvm_args = icu_arg
245        if args.device:
246            self.jsvm_args = ''
247        if self.builtin:
248            self.aot_args = f'{self.aot_args} --builtins-dts={self.builtin}.abc'
249        self.pgo = False
250        if args.pgo:
251            self.pgo = True
252            self.aot_args = (f'{self.aot_args} --enable-pgo-profiler=true --compiler-pgo-hotness-threshold={args.pgo_th}'
253                             f' --compiler-pgo-profiler-path=pgo_file_name.ap')
254        if args.frontend_args:
255            self.frontend_args = f'{self.frontend_args} {args.frontend_args}'
256        if args.aot_args:
257            self.aot_args = f'{self.aot_args} {args.aot_args}'
258        if args.jsvm_args:
259            self.jsvm_args = f'{self.jsvm_args} {args.jsvm_args}'
260        if args.info:
261            self.aot_args = f'{self.aot_args} --log-level=info'
262            self.jsvm_args = f'{self.jsvm_args} --log-level=info'
263        self.runner = ''
264        self.runnerd = 'gdb --args'
265        if self.arm64 or args.device:
266            if self.step[:3] != 'aot':
267                self.runner = 'qemu-aarch64'
268                self.runnerd = 'qemu-aarch64 -cpu max,sve=off -g 123456'
269            self.aot_args = f'{self.aot_args} --compiler-target-triple=aarch64-unknown-linux-gnu'
270        self.test_count = 0
271        self.fail_cases = []
272        os.environ['LD_LIBRARY_PATH'] = self.libs_dir
273        if args.env:
274            print(f'export LD_LIBRARY_PATH={self.libs_dir}')
275            sys.exit(0)
276        if args.copy_path:
277            run_and_print(f'hdc shell mount -o remount,rw /')
278            run_and_print(f'hdc file send {args.copy_path}\\ark_aot_compiler /system/bin/')
279            run_and_print(f'hdc shell chmod a+x /system/bin/ark_aot_compiler')
280            run_and_print(f'hdc file send {args.copy_path}\\ark_js_vm /system/bin/')
281            run_and_print(f'hdc shell chmod a+x /system/bin/ark_js_vm')
282            sys.exit(0)
283        if args.npm:
284            index_dir = f'{product_dir}/clang_x64/arkcompiler/ets_frontend/build/src'
285            os.system(f'cd {index_dir}/.. && npm install')
286            sys.exit(0)
287        if args.sign:
288            self.sign_hap(self.args.name)
289            sys.exit(0)
290
291    def run_cmd(self, cmd):
292        print(cmd)
293        ret = run_command(cmd, self.args.timeout)
294        if ret[0]:
295            print(ret[2])
296        return ret
297
298    def run_test(self, file):
299        self.test_count += 1
300        basename = os.path.basename(f'{file}')
301        type = os.path.splitext(basename)[-1]
302        name = os.path.splitext(basename)[0]
303        dir = os.path.dirname(file)
304        out_case_dir = f'{dir}'
305        hap_dir = 'null'
306        hap_name = 'null'
307        module_name = 'null'
308        if self.step == 'hap' or self.step == 'pack':
309            hap_dir = os.path.abspath(f'{out_case_dir}/..')
310            hap_name = os.path.basename(hap_dir)
311            module_name = get_module_name(hap_dir)
312        abc_file = f'{os.path.splitext(file)[0]}.abc'
313        if self.pgo:
314            pgo_file = f'{hap_dir}/ap/{module_name}'
315            self.aot_args = self.aot_args.replace('pgo_file_name', pgo_file)
316        cmd_map = {
317            'node': f'node {self.frontend_args} {file}',
318            'qjs': f'qjs {self.frontend_args} {file}',
319            'hermes': f'hermes {self.frontend_args} {file}',
320            'abc': f'{self.frontend} {self.frontend_args} {self.abcmode} --output {abc_file} {file}',
321            'pack': [f'mkdir -p {out_case_dir}/../an/arm64-v8a',
322                     f'mv {out_case_dir}/{name}.an {hap_dir}/an/arm64-v8a/{module_name}.an',
323                     f'mv {out_case_dir}/{name}.ai {hap_dir}/an/arm64-v8a/{module_name}.ai',
324                     f'cd {out_case_dir}/.. && rm -f ../{hap_name}.hap && zip -r -q ../{hap_name}.hap *',
325                     f'mv {hap_dir}/an/arm64-v8a/{module_name}.an {out_case_dir}/{name}.an',
326                     f'mv {hap_dir}/an/arm64-v8a/{module_name}.ai {out_case_dir}/{name}.ai',
327                     f'rm -rf {hap_dir}/an'],
328            'aot': f'{self.compiler} {self.aot_args} --aot-file={out_case_dir}/{name} {abc_file}',
329            'aotd': f'{self.runnerd} {self.compiler} {self.aot_args} --aot-file={out_case_dir}/{name} {abc_file}',
330            'run': f'{self.runner} {self.jsvm} {self.jsvm_args} --aot-file={out_case_dir}/{name} --entry-point={name} {abc_file}',
331            'rund': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --aot-file={out_case_dir}/{name} --entry-point={name} {abc_file}',
332            'asmint': f'{self.runner} {self.jsvm} {self.jsvm_args} --entry-point={name} {abc_file}',
333            'asmintd': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --entry-point={name} {abc_file}',
334            'int': f'{self.runner} {self.jsvm} {self.jsvm_args} --asm-interpreter=0 --entry-point={name} {abc_file}',
335            'intd': f'{self.runnerd} {self.jsvm} {self.jsvm_args} --asm-interpreter=0 --entry-point={name} {abc_file}',
336            'clean': f'rm -f {out_case_dir}/{name}.abc {out_case_dir}/{name}.an {out_case_dir}/{name}.ai',
337            'cleanhap': f'rm -rf {hap_dir}/an {out_case_dir}/{name}.an {out_case_dir}/{name}.ai'}
338        if self.builtin:
339            if self.frontend == self.ts2abc:
340                cmd = f'{self.ts2abc} {self.builtin}.ts -m --merge-abc -q -b'
341            elif self.frontend == self.es2abc:
342                cmd = (f'{self.es2abc} --module --merge-abc --extension=ts '
343                       f'--output={self.builtin}.abc {self.builtin}.ts')
344            print(cmd)
345            os.system(cmd)
346        if self.step == 'hap':
347            self.step = 'aot'
348            perf_start = time.perf_counter()
349            cmd = cmd_map[self.step]
350            print(cmd)
351            os.system(cmd)
352            perf_end = time.perf_counter()
353            abc_size = os.path.getsize(file) / 1024 / 1024
354            an_size = os.path.getsize(f'{out_case_dir}/{name}.an') / 1024 / 1024
355            print(f'test: {file}  abc_size: {abc_size: .1f}MB  an_size: {an_size:.1f}MB  '
356                  f'expand: {an_size / abc_size: .1f}  time: {perf_end - perf_start: .1f}s')
357            self.step = 'pack'
358        if self.step == 'pack':
359            for cmd in cmd_map[self.step]:
360                print(cmd)
361                os.system(cmd)
362            print(f'packed hap: {hap_name}.hap')
363            print(f'sign --------------------------------------------')
364            self.sign_hap(f'{hap_name}.hap')
365            return
366        if self.step == 'clean':
367            if os.path.isfile(f'{hap_dir}/{self.hap_abc}'):
368                self.step = 'cleanhap'
369        if self.args.tool == 'node':
370            ret = self.run_cmd(cmd_map['node'])
371            self.judge_test(file, ret)
372            return
373        if self.args.tool == 'qjs':
374            ret = self.run_cmd(cmd_map['qjs'])
375            self.judge_test(file, ret)
376            return
377        if self.args.tool == 'hermes':
378            ret = self.run_cmd(cmd_map['hermes'])
379            self.judge_test(file, ret)
380            return
381        if not self.args.tool:
382            self.args.tool = 'aot'
383        if self.args.tool not in ['aot', 'asmint', 'int']:
384            print(f'not supported tool: {self.args.tool}')
385            sys.exit(1)
386        if self.args.device:
387            ret = self.run_test_on_device(file)
388            return
389        if self.step != 'all':
390            # gdb should use the os.system
391            cmd = cmd_map[self.step]
392            print(cmd)
393            if self.arm64 and self.step[-1:] == 'd' and self.step[:3] != 'aot':
394                print(f'gdb-client start:   gdb-multiarch {self.jsvm}')
395                print(f'gdb-server connect: target remote:123456')
396            os.system(cmd)
397            return
398        ret = self.run_cmd(cmd_map['abc'])
399        if ret[0]:
400            self.judge_test(file, ret)
401            return
402        if self.args.tool == 'aot':
403            ret = self.run_cmd(cmd_map['aot'])
404            if ret[0] and ret[2].find('aot compile success') < 0:
405                self.judge_test(file, ret)
406                return
407            ret = self.run_cmd(cmd_map['run'])
408        else:
409            ret = self.run_cmd(cmd_map[self.args.tool])
410        self.judge_test(file, ret)
411
412    def run_test_on_device(self, file):
413        basename = os.path.basename(f'{file}')
414        name = os.path.splitext(basename)[0]
415        out_case_dir = '/data/test'
416        send_abc_file = f'{os.path.splitext(file)[0]}.abc'.replace('/', '\\')
417        abc_file = f'{out_case_dir}/{name}.abc'
418        cmd_map = {'abc': f'hdc file send {send_abc_file} {out_case_dir}/',
419                   'aot': f'hdc shell ark_aot_compiler {self.aot_args} --aot-file={out_case_dir}/{name} {abc_file}',
420                   'run': f'hdc shell ark_js_vm {self.jsvm_args} --aot-file={out_case_dir}/{name} --entry-point={name} {abc_file}',
421                   'asmint': f'hdc shell ark_js_vm {self.jsvm_args} --entry-point={name} {abc_file}',
422                   'int': f'hdc shell ark_js_vm {self.jsvm_args} --asm-interpreter=0 --entry-point={name} {abc_file}'}
423        if self.step != 'all':
424            run_and_print(cmd_map[self.step])
425            return
426        run_and_print(cmd_map['abc'])
427        if self.args.tool == 'aot':
428            ret = self.run_cmd(cmd_map['aot'])
429            if ret[0] and ret[2].find('aot compile success') < 0:
430                self.judge_test(file, ret)
431                return
432            ret = self.run_cmd(cmd_map['run'])
433        else:
434            ret = self.run_cmd(cmd_map[self.args.tool])
435        self.judge_test(file, ret)
436
437    def judge_test(self, file, out):
438        if out[0]:
439            self.fail_cases.append(file)
440            print_fail(f'FAIL: {file}')
441            return
442        expect_file = f'{os.path.dirname(file)}/{self.expect}'
443        if os.path.exists(expect_file):
444            with open(expect_file, mode='r') as infile:
445                expect = ''.join(infile.readlines()[13:])
446            if out[1].replace('\r', '') != expect.replace('\r', ''):
447                self.fail_cases.append(file)
448                print(f'expect: [{expect}]\nbut got: [{out[1]}]')
449                print_fail(f'FAIL: {file}')
450            else:
451                print_pass(f'PASS: {file}')
452        else:
453            print_pass(f'PASS: {file}')
454            print(out[1])
455
456    def report_test(self):
457        fail_count = len(self.fail_cases)
458        print(f'Ran tests: {self.test_count}')
459        print(f'Ran failed: {fail_count}')
460        if fail_count == 0:
461            print_pass('================================== All tests Run PASSED!')
462            return
463        print_fail('==================================')
464        for case in self.fail_cases:
465            print(case)
466        print_fail('==================================')
467
468    def find_file(self, dir, postfix_list):
469        result = []
470        for root, lists, files in os.walk(dir):
471            for file in files:
472                for postfix in postfix_list:
473                    path = os.path.join(root, file)
474                    found = path.find(postfix)
475                    if found == len(path) - len(postfix):
476                        result.append(path)
477        if os.path.isfile(dir):
478            for postfix in postfix_list:
479                found = dir.find(postfix)
480                if found == len(dir) - len(postfix):
481                    result.append(dir)
482                    break
483        return result
484
485    def test_hap(self):
486        if self.step != 'all':
487            return 1
488        files = self.find_file(self.args.name, [self.hap_abc, '.hap'])
489        if len(files):
490            self.step = 'hap'
491            file = files[0]
492            type = os.path.splitext(file)[-1]
493            if type == '.hap':
494                hap_dir = f'{os.path.splitext(file)[0]}.aot'
495                os.system(f'mkdir -p {hap_dir} && unzip -o -q {file} -d {hap_dir}')
496                file = f'{hap_dir}/{self.hap_abc}'
497            self.run_test(file)
498            return 0
499        return 1
500
501    def sign_hap(self, hap_name):
502        name = os.path.splitext(hap_name)[0]
503        sign_dir = f'{name}.sign'
504        sign_tool_dir = f'{self.ohdir}/developtools/hapsigner/dist'
505        name = os.path.splitext(sign_dir)[0]
506        self_dir = os.path.abspath(sys.argv[0])
507        os.system(f'mkdir -p {sign_dir} && unzip -o -q {hap_name} module.json -d {sign_dir}')
508        bundle_name = get_bundle_name(sign_dir)
509        if not self.args.sign or self.args.sign == 'system_core':
510            bundle_apl = 'system_core'
511            bundle_feature = 'hos_system_app'
512        elif self.args.sign == 'system_basic':
513            bundle_apl = self.args.sign
514            bundle_feature = 'hos_system_app'
515        elif self.args.sign == 'normal':
516            bundle_apl = self.args.sign
517            bundle_feature = 'hos_normal_app'
518        else:
519            print(f'sign not supported input: {self.args.sign}')
520            return 1
521        # modify sign config
522        data_load = []
523        data_save = []
524        sign_config = 'UnsgnedReleasedProfileTemplate.json'
525        with open(f'{sign_tool_dir}/{sign_config}') as f:
526            data_load = json.load(f)
527            data_load['bundle-info']['bundle-name'] = bundle_name
528            data_load['bundle-info']['apl'] = bundle_apl
529            data_load['bundle-info']['app-feature'] = bundle_feature
530            data_save = json.dumps(data_load)
531        with open(f'{sign_dir}/{sign_config}', 'w+') as f:
532            f.write(data_save)
533        # generate cert and sign
534        gen_cert = f'java -jar {sign_tool_dir}/hap-sign-tool.jar sign-profile -keyAlias "openharmony application profile release" -signAlg "SHA256withECDSA" -mode "localSign" -profileCertFile "{sign_tool_dir}/OpenHarmonyProfileRelease.pem" -inFile "{sign_dir}/{sign_config}" -keystoreFile "{sign_tool_dir}/OpenHarmony.p12" -outFile "{sign_dir}/openharmony.p7b" -keyPwd "123456" -keystorePwd "123456"'
535        sign_hap = f'java -jar {sign_tool_dir}/hap-sign-tool.jar sign-app -keyAlias "openharmony application release" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "{sign_tool_dir}/OpenHarmonyApplication.pem" -profileFile "{sign_dir}/openharmony.p7b" -inFile "{hap_name}" -keystoreFile "{sign_tool_dir}/OpenHarmony.p12" -outFile "{name}.sign.hap" -keyPwd "123456" -keystorePwd "123456"'
536        print(gen_cert)
537        print(sign_hap)
538        os.system(gen_cert)
539        os.system(sign_hap)
540        print(f'signed of {bundle_apl} for hap: {name}.sign.hap')
541
542    def test(self):
543        # run single test by name
544        files = []
545        if self.step not in self.types:
546            print(f'not supported step: {self.step}')
547            return 1
548        if not self.args.all:
549            files = self.find_file(self.args.name, self.types[self.step])
550            if len(files):
551                self.run_test(files[0])
552            elif self.test_hap():
553                print(f'only support file type: {self.types[self.step]}')
554                print(f'input path no test case: {self.args.name}')
555                return 1
556            return 0
557
558        # run all test in path
559        if not os.path.isdir(self.args.name):
560            print(f'input path not exists or is file: {self.args.name}')
561            return 1
562        files = self.find_file(self.args.name, self.types[self.step])
563        for test in files:
564            self.run_test(test)
565
566        if len(files) == 0:
567            self.test_hap()
568
569        if self.step == 'clean':
570            print('clean output files finished')
571            return 0
572
573        if self.test_count == 0:
574            print(f'input path no test case: {self.args.name}')
575            return 1
576
577        # output report
578        self.report_test()
579        return 0
580
581def print_pass(str):
582    print(f'\033[32;2m{str}\033[0m')
583    sys.stdout.flush()
584
585def print_fail(str):
586    print(f'\033[31;2m{str}\033[0m')
587    sys.stdout.flush()
588
589def main():
590    args = parse_args()
591    arktest = ArkTest(args)
592    return arktest.test()
593
594if __name__ == '__main__':
595    sys.exit(main())
596