diff --git a/examples/app_info/BUILD.gn b/examples/app_info/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..f19459b2349b6ca16af96de19ac4740db2f0a959 --- /dev/null +++ b/examples/app_info/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +############################################################################### +config("app_info_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_shared_library("app_info") { + sources = [] + public_configs = [ ":app_info_config" ] + subsystem_name = "subsystem_examples" +} +############################################################################### diff --git a/examples/app_info/test/BUILD.gn b/examples/app_info/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3f38132198b65c7429d0d2b5038a71d1c59149d0 --- /dev/null +++ b/examples/app_info/test/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +#################################group######################################### +group("unittest") { + testonly = true + deps = [] + + deps += [ "unittest/common/get_app_info:unittest" ] +} +############################################################################### diff --git a/examples/app_info/test/unittest/common/get_app_info/BUILD.gn b/examples/app_info/test/unittest/common/get_app_info/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3726abc1e0fda429a017e350918916508ace76af --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/BUILD.gn @@ -0,0 +1,40 @@ +# Copyright (C) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") + +module_output_path = "subsystem_examples/app_info" + +ohos_js_unittest("GetAppInfoTest") { + module_out_path = module_output_path + hap_profile = "./src/main/config.json" + deps = [ + ":app_info_js_assets", + ":app_info_resources", + ] + + certificate_profile = "//test/developertest/signature/openharmony_sx.p7b" + hap_name = "AppInfoJsTest" +} +ohos_js_assets("app_info_js_assets") { + source_dir = "./src/main/js/default" +} +ohos_resources("app_info_resources") { + sources = [ "./src/main/resources" ] + hap_profile = "./src/main/config.json" +} + +group("unittest") { + testonly = true + deps = [ ":GetAppInfoTest" ] +} diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/config.json b/examples/app_info/test/unittest/common/get_app_info/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..9889c145cf45093c6b938d34bb050c555653f09e --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/config.json @@ -0,0 +1,59 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/app.js b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/app.js new file mode 100644 index 0000000000000000000000000000000000000000..83cc355c87c42fd4f00b239657d2c081cf0e9aa0 --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/app.js @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import device from '@system.device'; + +export default { + onCreate() { + console.info('AceApplication onCreate'); + }, + onDestroy() { + console.info('AceApplication onDestroy'); + } +}; diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/en-US.json b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/en-US.json new file mode 100644 index 0000000000000000000000000000000000000000..e63c70d978a3a53be988388c87182f81785e170c --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/en-US.json @@ -0,0 +1,6 @@ +{ + "strings": { + "hello": "Hello", + "world": "World" + } +} \ No newline at end of file diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/zh-CN.json b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/zh-CN.json new file mode 100644 index 0000000000000000000000000000000000000000..de6ee5748322f44942c1b003319d8e66c837675f --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/i18n/zh-CN.json @@ -0,0 +1,6 @@ +{ + "strings": { + "hello": "您好", + "world": "世界" + } +} \ No newline at end of file diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.css b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.css new file mode 100644 index 0000000000000000000000000000000000000000..a6053c61f9615fcd50fefb51f878568f3e39e59b --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.css @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + left: 0px; + top: 0px; + width: 100%; + height: 100%; +} + +.title { + font-size: 60px; + text-align: center; + width: 100%; + height: 40%; + margin: 10px; +} +.btn { + width: 50%; + height: 100px; + font-size: 40px; +} diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.hml b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.hml new file mode 100644 index 0000000000000000000000000000000000000000..6069a046a35c4409ab85e4595a079a1670a9c7fe --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.hml @@ -0,0 +1,21 @@ + + +
+ + {{ $t('strings.hello') }} {{title}} + + +
diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.js b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.js new file mode 100644 index 0000000000000000000000000000000000000000..37d3d82171002a3214286dc10315e4baef40f4e6 --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/pages/index/index.js @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import app from '@system.app' + +import {Core, ExpectExtend} from 'deccjsunit/index' + +export default { + data: { + title: "" + }, + onInit() { + this.title = this.$t('strings.world'); + }, + onShow() { + console.info('onShow finish') + const core = Core.getInstance() + const expectExtend = new ExpectExtend({ + 'id': 'extend' + }) + + core.addService('expect', expectExtend) + core.init() + + const configService = core.getDefaultService('config') + configService.setConfig(this) + + require('../../test/List.test') + core.execute() + }, + onReady() { + }, +} diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/ExampleJsunit.test.js b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/ExampleJsunit.test.js new file mode 100644 index 0000000000000000000000000000000000000000..e80433862323a99fc8319121dd8c6dc08cbfb023 --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/ExampleJsunit.test.js @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import app from '@system.app' + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from 'deccjsunit/index' + +describe('appInfoTest', function () { + it('app_info_test_001', 0, function () { + var info = app.getInfo() + expect(info.versionName).assertEqual(info.versionName) + expect(info.versionCode).assertEqual(info.versionCode) + }) + it('app_info_test_002', 0, function () { + var info = app.getInfo() + expect(info != null).assertEqual(true) + }) + it('app_info_test_003', 0, function () { + var info = app.getInfo() + expect(info.versionName).assertEqual('') + expect(info.versionCode).assertEqual('0') + }) + +}) diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/List.test.js b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/List.test.js new file mode 100644 index 0000000000000000000000000000000000000000..62e348cb74788587609d9100918745cc71635dc2 --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/js/default/test/List.test.js @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +require('./ExampleJsunit.test.js') diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/element/string.json b/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..76e501f214f84c96a44d08973dbbdeab8515e1de --- /dev/null +++ b/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "app_name", + "value": "JsHelloWorld" + }, + { + "name": "mainability_description", + "value": "hap sample empty page" + } + ] +} \ No newline at end of file diff --git a/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/media/icon.png b/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/examples/app_info/test/unittest/common/get_app_info/src/main/resources/base/media/icon.png differ diff --git a/examples/ohos.build b/examples/ohos.build index ba3c3da48f4615e2475007e2da2f073c7286d5e9..8bea01699242c13464bc91aca3d9b2561e44603b 100755 --- a/examples/ohos.build +++ b/examples/ohos.build @@ -3,11 +3,13 @@ "parts": { "subsystem_examples": { "module_list": [ + "//test/developertest/examples/app_info:app_info", "//test/developertest/examples/detector:detector", "//test/developertest/examples/calculator:calculator", "//test/developertest/examples/calculator:calculator_static" ], "test_list": [ + "//test/developertest/examples/app_info/test:unittest", "//test/developertest/examples/calculator/test:unittest", "//test/developertest/examples/calculator/test:fuzztest", "//test/developertest/examples/detector/test:unittest", diff --git a/signature/openharmony_sx.p7b b/signature/openharmony_sx.p7b new file mode 100644 index 0000000000000000000000000000000000000000..9be1e98fa4c0c28ca997ed660112fa16b194f0f5 Binary files /dev/null and b/signature/openharmony_sx.p7b differ diff --git a/src/core/driver/drivers.py b/src/core/driver/drivers.py index 51e1cf6e573fc351a9fea572d1b7f8c9ed953872..66bef84ece8009a2b73174a2ac62a28d89e3e34b 100755 --- a/src/core/driver/drivers.py +++ b/src/core/driver/drivers.py @@ -16,20 +16,26 @@ # limitations under the License. # +import json import os import re +import shutil import time import platform +import zipfile from dataclasses import dataclass from xdevice import DeviceTestType from xdevice import DeviceLabelType from xdevice import ExecuteTerminate from xdevice import DeviceError +from xdevice import ShellHandler from xdevice import IDriver from xdevice import platform_logger from xdevice import Plugin +from xdevice import get_plugin +from xdevice_extension._core.constants import CommonParserType from core.utils import get_decode from core.utils import get_fuzzer_path from core.config.resource_manager import ResourceManager @@ -38,6 +44,7 @@ from core.config.config_manager import FuzzerConfigManager __all__ = [ "CppTestDriver", + "JSUnitTestDriver", "disable_keyguard", "GTestConst"] @@ -564,3 +571,239 @@ class CppTestDriver(IDriver): ############################################################################## ############################################################################## + +@Plugin(type=Plugin.DRIVER, id=DeviceTestType.jsunit_test) +class JSUnitTestDriver(IDriver): + """ + JSUnitTestDriver is a Test that runs a native test package on given device. + """ + + def __init__(self): + self.config = None + self.result = "" + self.start_time = None + self.ability_name = "" + self.package_name = "" + + def __check_environment__(self, device_options): + pass + + def __check_config__(self, config): + pass + + def __result__(self): + return self.result if os.path.exists(self.result) else "" + + def __execute__(self, request): + try: + LOG.info("developertest driver") + self.result = os.path.join(request.config.report_path, + "result", + '.'.join((request.get_module_name(), + "xml"))) + self.config = request.config + self.config.target_test_path = DEFAULT_TEST_PATH + self.config.device = request.config.environment.devices[0] + + suite_file = request.root.source.source_file + if not suite_file: + LOG.error("test source '%s' not exists" % + request.root.source.source_string) + return + + if not self.config.device: + result = ResultManager(suite_file, self.config) + result.set_is_coverage(False) + result.make_empty_result_file( + "No test device is found") + return + + package_name, ability_name = self._get_package_and_ability_name( + suite_file) + self.package_name = package_name + self.ability_name = ability_name + self.config.test_hap_out_path = \ + "/data/data/%s/files/" % self.package_name + + self._init_jsunit_test() + self._run_jsunit(suite_file) + self.generate_console_output(request) + + finally: + self.config.device.stop_catch_device_log() + + def _init_jsunit_test(self): + self.config.device.hdc_command("target mount") + self.config.device.execute_shell_command( + "rm -rf %s" % self.config.target_test_path) + self.config.device.execute_shell_command( + "mkdir -p %s" % self.config.target_test_path) + self.config.device.execute_shell_command( + "mount -o rw,remount,rw /%s" % "system") + self.config.device.hdc_command("shell hilog -r") + + + def _run_jsunit(self, suite_file): + filename = os.path.basename(suite_file) + + resource_manager = ResourceManager() + resource_data_dic, resource_dir = \ + resource_manager.get_resource_data_dic(suite_file) + resource_manager.process_preparer_data(resource_data_dic, resource_dir, + self.config.device) + + main_result = self._install_hap(suite_file) + result = ResultManager(suite_file, self.config) + + if main_result: + self._execute_hapfile_jsunittest() + self._uninstall_hap(self.package_name) + else: + self.result = result.get_test_results("Error: install hap failed") + LOG.error("Error: install hap failed") + + resource_manager.process_cleaner_data(resource_data_dic, resource_dir, + self.config.device) + + def generate_console_output(self, request): + report_name = request.get_module_name() + parsers = get_plugin( + Plugin.PARSER, CommonParserType.jsunit) + if parsers: + parsers = parsers[:1] + for listener in request.listeners: + listener.device_sn = self.config.device.device_sn + parser_instances = [] + + for parser in parsers: + parser_instance = parser.__class__() + parser_instance.suites_name = "{}_suites".format(report_name) + parser_instance.suites_name = request.listeners + parser_instance.listeners = request.listeners + parser_instances.append(parser_instance) + handler = ShellHandler(parser_instances) + + from xdevice_extension._core import utils + command = "hdc_std -t %s shell hilog -x " % self.config.device. \ + device_sn + + output = utils.start_standing_subprocess(command, return_result=True) + LOG.debug("start to parsing hilog") + handler.__read__(output) + handler.__done__() + + + def _execute_hapfile_jsunittest(self): + _unlock_screen(self.config.device) + _unlock_device(self.config.device) + + try: + return_message = self.start_hap_activity() + except (ExecuteTerminate, DeviceError) as exception: + return_message = str(exception.args) + + _lock_screen(self.config.device) + return return_message + + def _install_hap(self, suite_file): + message = self.config.device.hdc_command("install %s" % suite_file) + message = str(message).rstrip() + if message == "" or "success" in message: + return_code = True + if message != "": + LOG.info(message) + else: + return_code = False + if message != "": + LOG.warning(message) + + _sleep_according_to_result(return_code) + return return_code + + def start_hap_activity(self): + try: + command = "aa start -d 123 -a %s.MainAbility -b %s" \ + % (self.package_name, self.package_name) + self.start_time = time.time() + result_value = self.config.device.execute_shell_command( + command, timeout=TIME_OUT) + LOG.info("result_value [[[[[%s]]]]]" % result_value) + + if "success" in str(result_value).lower(): + LOG.info("execute %s's testcase success. result value=%s" + % (self.package_name, result_value)) + time.sleep(60) + else: + LOG.info("execute %s's testcase failed. result value=%s" + % (self.package_name, result_value)) + + _sleep_according_to_result(result_value) + return_message = result_value + except (ExecuteTerminate, DeviceError) as exception: + return_message = exception.args + + return return_message + + def _uninstall_hap(self, package_name): + return_message = self.config.device.execute_shell_command( + "bm uninstall -n %s" % package_name) + _sleep_according_to_result(return_message) + return return_message + + @staticmethod + def _get_package_and_ability_name(hap_filepath): + package_name = "" + ability_name = "" + + if os.path.exists(hap_filepath): + filename = os.path.basename(hap_filepath) + + #unzip the hap file + hap_bak_path = os.path.abspath(os.path.join( + os.path.dirname(hap_filepath), + "%s.bak" % filename)) + zf_desc = zipfile.ZipFile(hap_filepath) + try: + zf_desc.extractall(path=hap_bak_path) + except RuntimeError as error: + print(error) + zf_desc.close() + + #verify config.json file + app_profile_path = os.path.join(hap_bak_path, "config.json") + if not os.path.exists(app_profile_path): + print("file %s not exist" % app_profile_path) + return package_name, ability_name + + if os.path.isdir(app_profile_path): + print("%s is a folder, and not a file" % app_profile_path) + return package_name, ability_name + + #get package_name and ability_name value + load_dict = {} + with open(app_profile_path, 'r') as load_f: + load_dict = json.load(load_f) + profile_list = load_dict.values() + for profile in profile_list: + package_name = profile.get("package") + if not package_name: + continue + + abilities = profile.get("abilities") + for abilitie in abilities: + abilities_name = abilitie.get("name") + if abilities_name.startswith("."): + ability_name = package_name + abilities_name[ + abilities_name.find("."):] + else: + ability_name = abilities_name + break + break + + #delete hap_bak_path + if os.path.exists(hap_bak_path): + shutil.rmtree(hap_bak_path) + else: + print("file %s not exist" % hap_filepath) + + return package_name, ability_name diff --git a/src/core/testcase/testcase_manager.py b/src/core/testcase/testcase_manager.py index fcfa13ef3b7bc6b3cedf624c79bb50a8ac7162f7..d0ac52af924604fa789f25c1dff2895ea3282e7c 100755 --- a/src/core/testcase/testcase_manager.py +++ b/src/core/testcase/testcase_manager.py @@ -30,6 +30,7 @@ TESTFILE_TYPE_DATA_DIC = { "PYT": [], "CXX": [], "BIN": [], + "JST": [], } FILTER_SUFFIX_NAME_LIST = [".TOC", ".info", ".pyc"] @@ -109,7 +110,7 @@ class TestCaseManager(object): if suffix_name == ".dex": suite_file_dictionary["DEX"].append(suite_file) elif suffix_name == ".hap": - suite_file_dictionary["HAP"].append(suite_file) + suite_file_dictionary["JST"].append(suite_file) elif suffix_name == ".py": if not self.check_python_test_file(suite_file): continue