1#!/usr/bin/env python3
2# coding=utf-8
3
4#
5# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import os
20import sys
21import json
22import shutil
23import subprocess
24import platform
25
26from xdevice import platform_logger
27from core.utils import get_build_output_path
28from core.utils import get_output_path
29from core.utils import scan_support_product
30from core.common import is_open_source_product
31from core.config.config_manager import UserConfigManager
32
33BUILD_FILE_PATH = "./build_system.sh"
34BUILD_FILEPATH = "./build.sh"
35BUILD_LITE = "build/lite/build.py"
36BUILD_TARGET_PLATFORM = "build_platform=\"%s\""
37BUILD_PRODUCT_NAME = "product_name=%s"
38BUILD_TARGET_SUBSYSTEM = "target_subsystem=%s"
39BUILD_TARGET_SUITE = "suite=%s"
40LOG = platform_logger("BuildTestcases")
41
42
43##############################################################################
44##############################################################################
45
46class BuildTestcases(object):
47    def __init__(self, project_rootpath):
48        self.project_rootpath = project_rootpath
49        user_manager = UserConfigManager()
50        self.part_deps_path = os.path.join(sys.source_code_root_path,
51                                           "build",
52                                           "tools",
53                                           "module_dependence",
54                                           "part_deps.py")
55        self.is_build_example = user_manager.get_user_config_flag(
56            "build", "example")
57        self.build_parameter_dic = user_manager.get_user_config(
58            "build", "parameter")
59
60    @classmethod
61    def _copy_folder(cls, source_dir, target_dir):
62        if not os.path.exists(target_dir):
63            os.makedirs(target_dir)
64
65        if platform.system() == 'Windows':
66            command = ["xcopy", "/f", "/s", "/e", "/y",
67                       "/b", "/q", source_dir, target_dir]
68        else:
69            command = ["cp", "-rf", source_dir, target_dir]
70
71        LOG.info("command: %s" % str(command))
72        return subprocess.call(command) == 0
73
74    @classmethod
75    def _get_testcase_outname_by_productform(cls, productform):
76        if productform == "phone" or is_open_source_product(productform):
77            return ""
78
79        testcase_outpath = ""
80
81        # 路径注释 get_build_output_path = OpenHarmony/out/rk3568/build_configs/platforms_info/toolchain_to_variant.json
82        toolchain_filepath = os.path.join(
83            get_build_output_path(productform),
84            "build_configs",
85            "platforms_info",
86            "toolchain_to_variant.json")
87        if os.path.exists(toolchain_filepath):
88            data_dic = []
89            with open(toolchain_filepath, 'r') as toolchain_file:
90                data_dic = json.load(toolchain_file)
91                if not data_dic:
92                    LOG.warning("The %s file load error." %
93                                toolchain_filepath)
94                    data_dic = []
95            paltform_toolchain_dic = data_dic.get("platform_toolchain")
96            testcase_outpath = paltform_toolchain_dic.get(productform, "")
97            pos = testcase_outpath.rfind(':') + 1
98            testcase_outpath = testcase_outpath[pos:len(testcase_outpath)]
99        return testcase_outpath
100
101    @classmethod
102    def _delete_xts_testcase_dir(cls, para):
103        xts_testcase_out_dir = os.path.join(
104            get_build_output_path(para.productform),
105            "suites",
106            para.testtype[0],
107            "testcases")
108        LOG.info("xts_testcase_out_dir=%s" % xts_testcase_out_dir)
109        # 删除~/OpenHarmony/out/rk3568/suites/xts/testcases目录内容
110        if os.path.exists(xts_testcase_out_dir):
111            shutil.rmtree(xts_testcase_out_dir)
112
113    def build_fuzz_testcases(self, para):
114        self._delete_testcase_dir(para.productform)
115        helper_path = os.path.join("..", "libs", "fuzzlib", "fuzzer_helper.py")
116        command = [sys.executable, helper_path, 'make',
117                   'make_temp_test', para.productform]
118        if subprocess.call(command, shell=False) == 0:
119            build_result = True
120        else:
121            build_result = False
122        self._merge_testcase_dir(para.productform)
123        return build_result
124
125    # 编译测试用例(编译命令拼接)
126    def build_testcases(self, productform, target):
127        command = []
128        if self.is_build_example:
129            command.append("--gn-args")
130            command.append("build_example=true")
131        if isinstance(target, list):
132            for test in target:
133                command.append("--build-target")
134                command.append(test + "_test")
135        elif isinstance(target, str):
136            for test in target.split(','):
137                command.append("--build-target")
138                command.append(test)
139
140        if productform == "rk3568":
141            pass
142        else:
143            command.append("--abi-type")
144            command.append("generic_generic_arm_64only")
145            command.append("--device-type")
146            command.append(get_output_path().split("/")[-1])
147            command.append("--build-variant")
148            command.append("root")
149        command.append("--ccache")
150        self._delete_testcase_dir(productform)
151        build_result = self._execute_build_command(productform, command)
152        self._merge_testcase_dir(productform)
153        return build_result
154
155    # 编译XTS测试用例
156    def build_xts_testcases(self, para):
157        self._delete_xts_testcase_dir(para)
158        xts_build_command = []
159        if para.productform == "rk3568":
160            False
161        else:
162            xts_build_test_command = ["--abi-type", "generic_generic_arm_64only", "--device-type",
163                                      get_output_path().split("/")[-1], "--build-variant", "root", "--gn-args",
164                                      "build_xts=true", "--export-para", "xts_suitename:" + para.testtype[0]]
165            if len(para.subsystem) > 0:
166                input_subsystem = ",".join(para.subsystem)
167                xts_build_test_command.append("--build-target")
168                xts_build_test_command.append(input_subsystem)
169                return False
170            if para.testsuit != "" and len(para.subsystem) == 0:
171                LOG.error("Please specify subsystem.")
172                return False
173            xts_build_command.extend(xts_build_test_command)
174            xts_build_command.append("--ccache")
175        build_result = self._execute_build_xts_command(para, xts_build_command)
176        return build_result
177
178
179    def build_deps_files(self, productform):
180        command = ["--ccache", "--gn-args", "pycache_enable=true", "--gn-args",
181                   "check_deps=true", "--build-only-gn"]
182        if productform == "rk3568":
183            pass
184        else:
185            command.append("--abi-type")
186            command.append("generic_generic_arm_64only")
187            command.append("--device-type")
188            command.append(get_output_path().split("/")[-1])
189            command.append("--build-variant")
190            command.append("root")
191        return self._execute_build_deps_files_command(productform, command)
192
193    # 部件间依赖关系预处理,生成part_deps_info.json
194    def build_part_deps(self, para):
195        build_part_deps_result = self._execute_build_part_deps_command(para)
196        return build_part_deps_result
197
198    def build_gn_file(self, productform):
199        command = []
200        if self.is_build_example:
201            command.append("--gn-args")
202            command.append("build_example=true")
203        command.append("--build-only-gn")
204        command.append("--gn-args")
205        command.append(BUILD_TARGET_PLATFORM % productform)
206        return self._execute_build_command(productform, command)
207
208    def build_version(self, productform):
209        command = []
210        command.append("--build-target")
211        command.append("make_all")
212        command.append("--gn-args")
213        command.append(BUILD_TARGET_PLATFORM % productform)
214        return self._execute_build_command(productform, command)
215
216    def _delete_testcase_dir(self, productform):
217        if is_open_source_product(productform):
218            package_out_dir = os.path.join(
219                get_build_output_path(productform),
220                "packages",
221                "phone",
222                "tests")
223        else:
224            package_out_dir = os.path.join(
225                get_build_output_path(productform),
226                "packages",
227                productform,
228                "tests")
229
230        LOG.info("package_out_dir=%s" % package_out_dir)
231        # 删除~/OpenHarmony/out/rk3568/packages/phone/tests目录内容
232        if os.path.exists(package_out_dir):
233            shutil.rmtree(package_out_dir)
234
235        phone_out_dir = os.path.join(
236            self.project_rootpath, "out", "release", "tests")
237        LOG.info("phone_out_dir=%s" % phone_out_dir)
238        # 删除~/OpenHarmony/out/release/tests目录内容
239        if os.path.exists(phone_out_dir):
240            shutil.rmtree(phone_out_dir)
241
242        curr_productform_outname = self._get_testcase_outname_by_productform(
243            productform)
244        if curr_productform_outname == "":
245            return
246
247        curr_productform_outdir = os.path.join(
248            get_build_output_path(productform),
249            curr_productform_outname,
250            "tests")
251        LOG.info("curr_productform_outdir=%s" % curr_productform_outdir)
252        if os.path.exists(curr_productform_outdir):
253            shutil.rmtree(curr_productform_outdir)
254
255    def _merge_testcase_dir(self, productform):
256        if is_open_source_product(productform):
257            package_out_dir = os.path.join(
258                get_build_output_path(productform),
259                "packages",
260                "phone")
261        else:
262            package_out_dir = os.path.join(
263                get_build_output_path(productform),
264                "packages",
265                productform)
266        if platform.system() == 'Windows':
267            package_out_dir = os.path.join(package_out_dir, "tests")
268
269        phone_out_dir = os.path.join(get_build_output_path(productform),
270                                     "tests")
271        if os.path.exists(phone_out_dir):
272            self._copy_folder(phone_out_dir, package_out_dir)
273
274        curr_productform_outname = self._get_testcase_outname_by_productform(
275            productform)
276        if curr_productform_outname == "":
277            return
278
279        curr_productform_outdir = os.path.join(
280            get_build_output_path(productform),
281            curr_productform_outname,
282            "tests")
283        LOG.info("curr_productform_outdir=%s" % curr_productform_outdir)
284        if os.path.exists(curr_productform_outdir):
285            self._copy_folder(curr_productform_outdir, package_out_dir)
286
287    def _execute_build_command(self, productform, command):
288        build_result = False
289        current_path = os.getcwd()
290        os.chdir(self.project_rootpath)
291
292        if productform == "rk3568":
293            command.append("--product-name")
294            command.append(productform)
295        else:
296            global BUILD_FILEPATH
297            BUILD_FILEPATH = BUILD_FILE_PATH
298
299        if os.path.exists(BUILD_FILEPATH):
300            build_command = [BUILD_FILEPATH]
301            build_command.extend(command)
302            LOG.info("build_command: %s" % str(build_command))
303            if subprocess.call(build_command) == 0:
304                build_result = True
305            else:
306                build_result = False
307        else:
308            LOG.warning("Error: The %s is not exist" % BUILD_FILEPATH)
309
310        os.chdir(current_path)
311        return build_result
312
313    def _execute_build_deps_files_command(self, productform, command):
314        build_deps_files_result = False
315        current_path = os.getcwd()
316        os.chdir(self.project_rootpath)
317
318        if productform == "rk3568":
319            command.append("--product-name")
320            command.append(productform)
321        else:
322            global BUILD_FILEPATH
323            BUILD_FILEPATH = BUILD_FILE_PATH
324
325        if os.path.exists(BUILD_FILEPATH):
326            build_deps_files_command = [BUILD_FILEPATH]
327            build_deps_files_command.extend(command)
328            LOG.info("build_deps_files_command: %s" % str(build_deps_files_command))
329            if subprocess.call(build_deps_files_command) == 0:
330                build_deps_files_result = True
331            else:
332                build_deps_files_result = False
333        else:
334            LOG.warning("Build Deps Files Error: The %s is not exist" % BUILD_FILEPATH)
335
336        os.chdir(current_path)
337        return build_deps_files_result
338
339    def _execute_build_part_deps_command(self, para):
340        build_part_deps_result = False
341        build_part_deps_command = []
342        current_path = os.getcwd()
343        # 路径 deps_files_path = ~/OpenHarmony/out/baltimore/deps_files
344        os.chdir(self.project_rootpath)
345        if para.productform == "rk3568":
346            deps_files_path = os.path.abspath(os.path.join(
347                get_build_output_path(para.productform), "deps_files"))
348        else:
349            deps_files_path = os.path.abspath(os.path.join(
350                "out", get_output_path(), "deps_files"))
351        LOG.info("deps_files_path: %s" % deps_files_path)
352        build_part_deps_command.append(self.part_deps_path)
353        build_part_deps_command.append("--deps-files-path")
354
355        if os.path.exists(deps_files_path):
356            build_part_deps_command.append(deps_files_path)
357            LOG.info("build_part_deps_command: %s" % str(build_part_deps_command))
358            if subprocess.call(build_part_deps_command) == 0:
359                build_part_deps_result = True
360            else:
361                build_part_deps_result = False
362        else:
363            LOG.warning("Build Part Deps Info Error: The %s is not exist" % deps_files_path)
364
365        os.chdir(current_path)
366        return build_part_deps_result
367
368    def _execute_build_xts_command(self, para, xts_build_command):
369        build_result = False
370        current_path = os.getcwd()
371        # eg.路径 acts_rootpath = ~/OpenHarmony/test/xts/acts
372        xts_project_rootpath = os.path.join(sys.source_code_root_path,
373                                            "test",
374                                            "xts",
375                                            para.testtype[0])
376        os.chdir(self.project_rootpath)
377        if para.productform == "rk3568":
378            os.chdir(xts_project_rootpath)
379            xts_build_command.append(BUILD_PRODUCT_NAME % para.productform)
380            xts_build_command.append("system_size=standard")
381            if len(para.subsystem) > 0:
382                input_subsystem = ",".join(para.subsystem)
383                xts_build_command.append(BUILD_TARGET_SUBSYSTEM % input_subsystem)
384            if para.testsuit != "" and len(para.subsystem) == 0:
385                LOG.error("Please specify subsystem.")
386                return False
387        else:
388            global BUILD_FILEPATH
389            BUILD_FILEPATH = BUILD_FILE_PATH
390
391        if os.path.exists(BUILD_FILEPATH):
392            build_command = [BUILD_FILEPATH]
393            build_command.extend(xts_build_command)
394            LOG.info("build_xts_command: %s" % str(build_command))
395            if subprocess.call(build_command) == 0:
396                build_result = True
397            else:
398                build_result = False
399        else:
400            LOG.warning("Build XTS Testcase Error: The %s is not exist" % BUILD_FILEPATH)
401
402        os.chdir(current_path)
403        return build_result
404
405##############################################################################
406##############################################################################
407