• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -- coding: utf-8 --
3#
4# Copyright (c) 2024-2025 Huawei Device Co., Ltd.
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
17import argparse
18import multiprocessing
19from functools import cached_property
20from pathlib import Path
21from typing import Any, cast
22
23from runner.common_exceptions import InvalidConfiguration
24from runner.enum_types.qemu import QemuKind
25from runner.enum_types.verbose_format import VerboseFilter, VerboseKind
26from runner.options.macros import Macros
27from runner.options.options import IOptions
28from runner.options.options_coverage import CoverageOptions
29from runner.options.options_time_report import TimeReportOptions
30from runner.reports.report_format import ReportFormat
31from runner.utils import convert_underscore
32
33
34class GeneralOptions(IOptions):
35    __DEFAULT_PROCESSES = 1
36    __DEFAULT_CHUNKSIZE = 32
37    __DEFAULT_GC_TYPE = "g1-gc"
38    __DEFAULT_GC_BOMBING_FREQUENCY = 0
39    __DEFAULT_HEAP_VERIFIER = "fail_on_verification"
40    __DEFAULT_REPORT_FORMAT = ReportFormat.LOG
41    __DEFAULT_DETAILED_REPORT_FILE = "detailed-report-file"
42    __DEFAULT_VERBOSE = VerboseKind.SILENT
43    __DEFAULT_VERBOSE_FILTER = VerboseFilter.NEW_FAILURES
44    __DEFAULT_QEMU = QemuKind.NONE
45    __DEFAULT_SHOW_PROGRESS = False
46    __DEFAULT_DETAILED_REPORT = False
47    __DEFAULT_REPORT_DIR = "report"
48    __CFG_RUNNER = "runner"
49
50    __VERBOSE = "verbose"
51    __VERBOSE_FILTER = "verbose-filter"
52    __PROCESSES = "processes"
53    __CHUNKSIZE = "chunksize"
54    __DETAILED_REPORT = "detailed-report"
55    __DETAILED_REPORT_FILE = "detailed-report-file"
56    __SHOW_PROGRESS = "show-progress"
57    __QEMU = "qemu"
58    __REPORT_DIR = "report-dir"
59
60    def __init__(self, data: dict[str, Any], parent: IOptions):  # type: ignore[explicit-any]
61        super().__init__(data)
62        self.__parameters: dict[str, Any] = {}  # type: ignore[explicit-any]
63        self._parent = parent
64        for param_name, param_value in data.items():
65            if param_name.startswith(self.__CFG_RUNNER):
66                param_name = convert_underscore(param_name.replace(f"{self.__CFG_RUNNER}.", ""))
67                self.__parameters[param_name] = param_value
68        self.time_report = TimeReportOptions(self.__parameters)
69        self.coverage = CoverageOptions(self.__parameters)
70
71    def __str__(self) -> str:
72        return self._to_str(indent=1)
73
74    @staticmethod
75    def add_cli_args(parser: argparse.ArgumentParser) -> None:
76        parser.add_argument(
77            f'--{GeneralOptions.__PROCESSES}', '-j', default=GeneralOptions.__DEFAULT_PROCESSES,
78            help=f'Number of processes to use in parallel. By default {GeneralOptions.__DEFAULT_PROCESSES}. '
79                 'Special value `all` - means to use all available processes')
80        parser.add_argument(
81            f'--{GeneralOptions.__DETAILED_REPORT}', action='store_true',
82            default=GeneralOptions.__DEFAULT_DETAILED_REPORT,
83            help='Create additional detailed report with counting tests for each folder.')
84        parser.add_argument(
85            f'--{GeneralOptions.__DETAILED_REPORT_FILE}', action='store',
86            default=GeneralOptions.__DEFAULT_DETAILED_REPORT_FILE,
87            help='Name of additional detailed report. By default, the report is created at '
88                 '$WorkDir/<suite-name>/report/<suite-name>_detailed-report-file.md , '
89                 'where $WorkDir is the folder specified by the environment variable WORK_DIR')
90        parser.add_argument(
91            f'--{GeneralOptions.__REPORT_DIR}', action='store',
92            default=GeneralOptions.__DEFAULT_REPORT_DIR,
93            help='Name of report folder under $WorkDir. By default, the name is "report".'
94                 'The location is "$WorkDir/<suite-name>/<report-dir>", '
95                 'where $WorkDir is the folder specified by the environment variable WORK_DIR')
96        parser.add_argument(
97            f'--{GeneralOptions.__SHOW_PROGRESS}', action='store_true',
98            default=GeneralOptions.__DEFAULT_SHOW_PROGRESS,
99            help='Show progress bar')
100        parser.add_argument(
101            f'--{GeneralOptions.__VERBOSE}', '-v', action='store',
102            default=GeneralOptions.__DEFAULT_VERBOSE,
103            type=lambda arg: VerboseKind.is_value(arg, f"--{GeneralOptions.__VERBOSE}"),
104            help='Enable verbose output. '
105                 f'Possible values one of: {VerboseKind.values()}. Where '
106                 'all - the most detailed output, '
107                 'short - test status and output, '
108                 'silent - only test status for new failed tests (by default)')
109        parser.add_argument(
110            f'--{GeneralOptions.__VERBOSE_FILTER}', action='store',
111            default=GeneralOptions.__DEFAULT_VERBOSE_FILTER,
112            type=lambda arg: VerboseFilter.is_value(arg, f"--{GeneralOptions.__VERBOSE_FILTER}"),
113            help='Filter for what kind of tests to output stdout and stderr. Works only when --verbose option is set.'
114                 f'Supported values: {VerboseFilter.values()}. Where '
115                 'all - for all executed tests, '
116                 'ignored - for new failures and tests from ignored test lists both passed and failed. '
117                 'new - only for new failures (by default).')
118        parser.add_argument(
119            f'--{GeneralOptions.__QEMU}', action='store',
120            default=GeneralOptions.__DEFAULT_QEMU,
121            type=lambda arg: QemuKind.is_value(arg, f"--{GeneralOptions.__QEMU}"),
122            help='Launch all binaries in qemu aarch64 (arm64) or arm (arm32)')
123
124        TimeReportOptions.add_cli_args(parser)
125        CoverageOptions.add_cli_args(parser)
126
127    @cached_property
128    def processes(self) -> int:
129        procs = self.__parameters.get(self.__PROCESSES, self.__DEFAULT_PROCESSES)
130        if isinstance(procs, str) and procs.lower() == "all":
131            self.__parameters[self.__PROCESSES] = multiprocessing.cpu_count()
132        return int(self.__parameters.get(self.__PROCESSES, self.__DEFAULT_PROCESSES))
133
134    @cached_property
135    def build(self) -> Path:
136        build_path = Macros.expand_macros_in_path("${PANDA_BUILD}", self)
137        if build_path is None:
138            raise InvalidConfiguration("Build path is not set.")
139        return Path(build_path).expanduser()
140
141    @cached_property
142    def chunksize(self) -> int:
143        return GeneralOptions.__DEFAULT_CHUNKSIZE
144
145    @cached_property
146    def static_core_root(self) -> Path:
147        runtime_core_path = cast(str, Macros.expand_macros_in_path("${ARKCOMPILER_RUNTIME_CORE_PATH}", self))
148        static_core_path = Path(runtime_core_path) / "static_core"
149        return static_core_path
150
151    @cached_property
152    def show_progress(self) -> bool:
153        return cast(bool, self.__parameters.get(self.__SHOW_PROGRESS, self.__DEFAULT_SHOW_PROGRESS))
154
155    @cached_property
156    def report_format(self) -> ReportFormat:
157        return GeneralOptions.__DEFAULT_REPORT_FORMAT
158
159    @cached_property
160    def detailed_report(self) -> bool:
161        return cast(bool, self.__parameters.get(self.__DETAILED_REPORT, self.__DEFAULT_DETAILED_REPORT))
162
163    @cached_property
164    def detailed_report_file(self) -> Path | None:
165        path_str = self.__parameters.get(self.__DETAILED_REPORT_FILE, self.__DEFAULT_DETAILED_REPORT_FILE)
166        if path_str:
167            return Path(cast(str, path_str))
168        return None
169
170    @cached_property
171    def report_dir_name(self) -> str:
172        return cast(str, self.__parameters.get(self.__REPORT_DIR, self.__DEFAULT_REPORT_DIR))
173
174    @cached_property
175    def verbose(self) -> VerboseKind:
176        kind = self.__parameters.get(self.__VERBOSE, self.__DEFAULT_VERBOSE)
177        if isinstance(kind, VerboseKind):
178            return kind
179        raise InvalidConfiguration("Verbose kind has incorrect value")
180
181    @cached_property
182    def verbose_filter(self) -> VerboseFilter:
183        kind = self.__parameters.get(self.__VERBOSE_FILTER, self.__DEFAULT_VERBOSE_FILTER)
184        if isinstance(kind, VerboseFilter):
185            return kind
186        raise InvalidConfiguration("Verbose filter has incorrect value")
187
188    @cached_property
189    def qemu(self) -> QemuKind:
190        kind = self.__parameters.get(self.__QEMU, self.__DEFAULT_QEMU)
191        if isinstance(kind, QemuKind):
192            return kind
193        raise InvalidConfiguration("Qemu kind has incorrect value")
194
195    @cached_property
196    def aot_check(self) -> bool:
197        return False
198
199    def get_command_line(self) -> str:
200        options = [
201            f'--processes={self.processes}' if self.processes != GeneralOptions.__DEFAULT_PROCESSES else '',
202            f'--chunksize={self.chunksize}' if self.chunksize != GeneralOptions.__DEFAULT_CHUNKSIZE else '',
203            '--show-progress' if self.show_progress else '',
204            f'--verbose={self.verbose.value}'
205            if self.verbose != GeneralOptions.__DEFAULT_VERBOSE else '',
206            f'--verbose-filter={self.verbose_filter.value}'
207            if self.verbose_filter != GeneralOptions.__DEFAULT_VERBOSE_FILTER else '',
208            self.coverage.get_command_line(),
209            '--aot' if self.aot_check else '',
210            self.time_report.get_command_line(),
211        ]
212        return ' '.join(options)
213