!1036 merge OpenHarmony-6.1-LTS into OpenHarmony-6.1-LTS
将7885冒烟测试用例合入 LTS,仅包括开机启动等基础测试用例,不包括系统应用用例 Created-by: xkchen0104 Commit-by: xiang-kai-chen Merged-by: openharmony_ci Description: ### 一、内容说明(相关的Issue) https://gitcode.com/openharmony/developtools_integration_verification/issues/583 ### 二、建议测试周期和提测地址 建议测试完成时间:xxxx.xx.xx 投产上线时间:xxxx.xx.xx 提测地址:CI环境/压测环境 测试账号: ### 三、变更内容 * 3.1 关联PR列表 * 3.2 数据库和部署说明 1. 常规更新 2. 重启unicorn 3. 重启sidekiq 4. 迁移任务:是否有迁移任务,没有写 "无" 5. rake脚本:`bundle exec xxx RAILS_ENV = production`;没有写 "无" * 3.4 其他技术优化内容(做了什么,变更了什么) - 重构了 xxxx 代码 - xxxx 算法优化 * 3.5 废弃通知(什么字段、方法弃用?) * 3.6 后向不兼容变更(是否有无法向后兼容的变更?) ### 四、研发自测点(自测哪些?冒烟用例全部自测?) 自测测试结论: ### 五、测试关注点(需要提醒QA重点关注的、可能会忽略的地方) 检查点: | 需求名称 | 是否影响xx公共模块 | 是否需要xx功能 | 需求升级是否依赖其他子产品 | |------|------------|----------|---------------| | xxx | 否 | 需要 | 不需要 | | | | | | 接口测试: 性能测试: 并发测试: 其他: See merge request: openharmony/developtools_integration_verification!1036
@@ -0,0 +1,67 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from utils.device import Device
|
||||
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--sn', default='')
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def device(request):
|
||||
sn = request.config.option.sn
|
||||
return Device(sn)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def setup_teardown(request, device):
|
||||
# logging.info('setup--------')
|
||||
current_case = os.path.basename(request.path)[:-3]
|
||||
# 日志截图等保存路径
|
||||
device.report_path = os.path.realpath(os.path.dirname(request.config.option.htmlpath))
|
||||
logging.info('set current report path as {}'.format(device.report_path))
|
||||
device.resource_path = os.path.join(os.path.dirname(__file__), 'resource')
|
||||
os.makedirs(device.report_path, exist_ok=True)
|
||||
# device.rm_faultlog()
|
||||
# device.start_hilog()
|
||||
device.wakeup()
|
||||
device.unlock()
|
||||
time.sleep(2)
|
||||
device.set_power_mode()
|
||||
device.set_screen_timeout()
|
||||
device.unlock()
|
||||
time.sleep(5)
|
||||
#device.go_home()
|
||||
time.sleep(1)
|
||||
if device.get_focus_window() == 'SystemDialog1':
|
||||
# 使用相对坐标(屏幕中心)
|
||||
device.click(device.width // 2, int(device.height * 0.625))
|
||||
time.sleep(2)
|
||||
if device.get_focus_window() == 'SystemDialog1':
|
||||
rst = device.hdc_shell(f'ps -ef | grep -w com.ohos.systemui | grep -v grep')
|
||||
rst_list = rst.split()
|
||||
logging.info(f'Process ID: {rst_list[1]}')
|
||||
device.hdc_shell(f'kill -9 {rst_list[1]}')
|
||||
#device.click(595, 555)
|
||||
time.sleep(5)
|
||||
device.unlock()
|
||||
#device.click(360, 800)
|
||||
device.click(device.width // 2, int(device.height * 0.972))
|
||||
time.sleep(1)
|
||||
#device.click(360, 1245)
|
||||
|
||||
|
||||
yield
|
||||
|
||||
# logging.info('后置操作')
|
||||
device.go_home()
|
||||
logging.info('clear recent task')
|
||||
device.clear_recent_task()
|
||||
device.clean_app_data(request.param)
|
||||
# device.stop_and_collect_hilog()
|
||||
@@ -0,0 +1,71 @@
|
||||
import argparse
|
||||
import json
|
||||
import os.path
|
||||
import platform
|
||||
import re
|
||||
import traceback
|
||||
|
||||
import pytest
|
||||
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def distribute_testcase(test_num):
|
||||
with open(os.path.join(BASE_DIR, 'testcases.json'), 'r', encoding='utf-8') as f:
|
||||
test_cases_list = [case.get('case_file') for case in json.load(f)]
|
||||
if test_num == '1/2':
|
||||
selected = test_cases_list[0:1] + test_cases_list[8:]
|
||||
elif test_num == '2/2':
|
||||
selected = test_cases_list[0:8]
|
||||
else:
|
||||
selected = test_cases_list
|
||||
return selected
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='manual to this scription')
|
||||
parser.add_argument('--test_num', type=str, default='1/1')
|
||||
parser.add_argument('--save_path', type=str, default='./report')
|
||||
parser.add_argument('--device_num', type=str, default='')
|
||||
args = parser.parse_args()
|
||||
|
||||
test_num = args.test_num
|
||||
sn = args.device_num
|
||||
save_path = os.path.join(args.save_path, sn)
|
||||
|
||||
print('[current dir]{}'.format(os.getcwd()))
|
||||
|
||||
run_params = ['-vs', '--sn={}'.format(sn)]
|
||||
|
||||
try:
|
||||
|
||||
# 报告保存路径
|
||||
report = os.path.join(args.save_path, '{}_report.html'.format(sn))
|
||||
run_params.extend(['--html={}'.format(report), '--self-contained-html', '--capture=sys'])
|
||||
|
||||
# 用例选择
|
||||
selected_cases = distribute_testcase(test_num)
|
||||
run_params.extend(selected_cases)
|
||||
|
||||
print(run_params)
|
||||
pytest.main(run_params)
|
||||
|
||||
system = platform.system().lower()
|
||||
if system.startswith('win'):
|
||||
encoding = 'gbk'
|
||||
else:
|
||||
encoding = 'utf-8'
|
||||
|
||||
with open(report, 'r+', encoding=encoding) as f:
|
||||
text = f.read()
|
||||
passed = int(re.findall(r'<span class="passed">(\d+)\s*passed', text, re.I)[0])
|
||||
# if encoding == 'gbk':
|
||||
# text = text.replace('<meta charset="utf-8"/>', '<meta charset="gbk"/>')
|
||||
# f.seek(0)
|
||||
# f.write(text)
|
||||
if passed == len(selected_cases):
|
||||
print('SmokeTest: End of check, test succeeded!')
|
||||
else:
|
||||
print('SmokeTest: End of check, SmokeTest find some fatal problems! passed {}/{}'.format(passed, len(selected_cases)))
|
||||
except:
|
||||
print('SmokeTest: End of check, SmokeTest find some fatal problems! {}'.format(traceback.format_exc()))
|
||||
@@ -0,0 +1,5 @@
|
||||
[pytest]
|
||||
log_cli = true
|
||||
log_cli_level = DEBUG
|
||||
log_cli_format = [%(asctime)s][%(thread)d][%(levelname)s] %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
@@ -0,0 +1,415 @@
|
||||
[
|
||||
{
|
||||
"processName": "hiview",
|
||||
"acls": [
|
||||
"ohos.permission.DUMP",
|
||||
"ohos.permission.GET_WIFI_PEERS_MAC",
|
||||
"ohos.permission.MANAGE_RGM",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION",
|
||||
"ohos.permission.CAPTURE_SCREEN"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "privacy_service",
|
||||
"acls": [
|
||||
"ohos.permission.CAMERA_CONTROL",
|
||||
"ohos.permission.MANAGE_DISPOSED_APP_STATUS",
|
||||
"ohos.permission.MICROPHONE_CONTROL",
|
||||
"ohos.permission.PERMISSION_RECORD_TOGGLE",
|
||||
"ohos.permission.USE_SECURITY_PRIVACY_MESSAGER",
|
||||
"ohos.permission.SET_SUPER_PRIVACY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "inputmethod_service",
|
||||
"acls": [
|
||||
"ohos.permission.INPUT_MONITORING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "memmgrservice",
|
||||
"acls": [
|
||||
"ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS_EXTENSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "locationhub",
|
||||
"acls": [
|
||||
"ohos.permission.GET_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.GET_WIFI_PEERS_MAC"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "useriam",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_AUTH_RESPOOL",
|
||||
"ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS_EXTENSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "pinauth",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_AUTH_RESPOOL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "foundation",
|
||||
"acls": [
|
||||
"ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT",
|
||||
"ohos.permission.PERMISSION_START_ABILITIES_FROM_BACKGROUND",
|
||||
"ohos.permission.GRANT_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.GRANT_URI_PERMISSION_PRIVILEGED",
|
||||
"ohos.permission.SET_SANDBOX_POLICY",
|
||||
"ohos.permission.REVOKE_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.MANAGE_HAP_TOKENID",
|
||||
"ohos.permission.START_INVISIBLE_ABILITY",
|
||||
"ohos.permission.INPUT_MONITORING",
|
||||
"ohos.permission.INSTALL_SANDBOX_BUNDLE",
|
||||
"ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS_EXTENSION",
|
||||
"ohos.permission.MANAGE_USER_ACCOUNT_INFO",
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.SET_SUPER_PRIVACY",
|
||||
"ohos.permission.MANAGE_MISSIONS",
|
||||
"ohos.permission.CAPTURE_SCREEN",
|
||||
"ohos.permission.PUBLISH_DISPLAY_ROTATION_EVENT",
|
||||
"ohos.permission.PUBLISH_CAST_PLUGGED_EVENT",
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER",
|
||||
"ohos.permission.NOTIFICATION_AGENT_CONTROLLER",
|
||||
"ohos.permission.ACCESS_SCREEN_LOCK_INNER"
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "dscreen",
|
||||
"acls": [
|
||||
"ohos.permission.CAPTURE_SCREEN"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "sensors",
|
||||
"acls": [
|
||||
"ohos.permission.GET_SENSITIVE_PERMISSIONS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "camera_service",
|
||||
"acls": [
|
||||
"ohos.permission.GET_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.SET_MUTE_POLICY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "audio_server",
|
||||
"acls": [
|
||||
"ohos.permission.SET_FOREGROUND_HAP_REMINDER",
|
||||
"ohos.permission.GET_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.SET_MUTE_POLICY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "msdp",
|
||||
"acls": [
|
||||
"ohos.permission.INPUT_MONITORING",
|
||||
"ohos.permission.ACCESS_DISTRIBUTED_HARDWARE",
|
||||
"ohos.permission.INTERCEPT_INPUT_EVENT",
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.MANAGE_MOUSE_CURSOR",
|
||||
"ohos.permission.INJECT_INPUT_EVENT",
|
||||
"ohos.permission.FILTER_INPUT_EVENT",
|
||||
"ohos.permission.CAPTURE_SCREEN",
|
||||
"ohos.permission.QUERY_ACCESSIBILITY_ELEMENT",
|
||||
"ohos.permission.ACCESS_EXT_SYSTEM_ABILITY",
|
||||
"ohos.permission.GET_PAGE_INFO"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "dslm_service",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_IDS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "accountmgr",
|
||||
"acls": [
|
||||
"ohos.permission.ENFORCE_USER_IDM",
|
||||
"ohos.permission.STORAGE_MANAGER_CRYPT",
|
||||
"ohos.permission.CAPTURE_SCREEN"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "hdcd",
|
||||
"acls": [
|
||||
"ohos.permission.GET_BUNDLE_INFO_PRIVILEGED",
|
||||
"ohos.permission.INSTALL_BUNDLE",
|
||||
"ohos.permission.LISTEN_BUNDLE_CHANGE",
|
||||
"ohos.permission.CHANGE_ABILITY_ENABLED_STATE",
|
||||
"ohos.permission.REMOVE_CACHE_FILES",
|
||||
"ohos.permission.START_ABILITIES_FROM_BACKGROUND",
|
||||
"ohos.permission.PERMISSION_USED_STATS",
|
||||
"ohos.permission.DUMP",
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER",
|
||||
"ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT",
|
||||
"ohos.permission.CLEAN_APPLICATION_DATA",
|
||||
"ohos.permission.START_SYSTEM_DIALOG",
|
||||
"ohos.permission.GET_RUNNING_INFO",
|
||||
"ohos.permission.CONTROL_SVC_CMD",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION",
|
||||
"ohos.permission.INSTALL_PLUGIN_BUNDLE",
|
||||
"ohos.permission.UNINSTALL_PLUGIN_BUNDLE",
|
||||
"ohos.permission.HIVIEW_TRACE_MANAGE",
|
||||
"ohos.permission.NETWORK_SIMULATE",
|
||||
"ohos.permission.GET_WIFI_INFO",
|
||||
"ohos.permission.SET_WIFI_CONFIG",
|
||||
"ohos.permission.GET_WIFI_INFO_INTERNAL",
|
||||
"ohos.permission.MANAGE_ENTERPRISE_WIFI_CONNECTION",
|
||||
"ohos.permission.INSTALL_ALLOW_DOWNGRADE",
|
||||
"ohos.permission.START_INVISIBLE_ABILITY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "softbus_server",
|
||||
"acls": [
|
||||
"ohos.permission.GET_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.ACCESS_IDS",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION",
|
||||
"ohos.permission.GET_WIFI_PEERS_MAC",
|
||||
"ohos.permission.GET_WIFI_INFO_INTERNAL",
|
||||
"ohos.permission.ACCESS_DEVAUTH_CRED_PRIVILEGE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "backup_sa",
|
||||
"acls": [
|
||||
"ohos.permission.INSTALL_BUNDLE",
|
||||
"ohos.permission.ACCESS_EXT_SYSTEM_ABILITY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "media_service",
|
||||
"acls": [
|
||||
"ohos.permission.CAPTURE_SCREEN"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "security_component_service",
|
||||
"acls": [
|
||||
"ohos.permission.GRANT_SENSITIVE_PERMISSIONS",
|
||||
"ohos.permission.REVOKE_SENSITIVE_PERMISSIONS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "distributedsched",
|
||||
"acls": [
|
||||
"ohos.permission.INPUT_MONITORING",
|
||||
"ohos.permission.MANAGE_MISSIONS",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION",
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.START_INVISIBLE_ABILITY",
|
||||
"ohos.permission.CONNECT_DISTRIBUTED_EXTENSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "accessibility",
|
||||
"acls": [
|
||||
"ohos.permission.INTERCEPT_INPUT_EVENT",
|
||||
"ohos.permission.MANAGE_MOUSE_CURSOR",
|
||||
"ohos.permission.FILTER_INPUT_EVENT",
|
||||
"ohos.permission.INJECT_INPUT_EVENT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "dlp_permission_service",
|
||||
"acls": [
|
||||
"ohos.permission.INSTALL_SANDBOX_BUNDLE",
|
||||
"ohos.permission.UNINSTALL_SANDBOX_BUNDLE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "quick_fix",
|
||||
"acls": [
|
||||
"ohos.permission.INSTALL_QUICK_FIX_BUNDLE",
|
||||
"ohos.permission.UNINSTALL_QUICK_FIX_BUNDLE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "hidumper_service",
|
||||
"acls": [
|
||||
"ohos.permission.DUMP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "sharing_service",
|
||||
"acls": [
|
||||
"ohos.permission.CAPTURE_SCREEN",
|
||||
"ohos.permission.GET_WIFI_PEERS_MAC",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "pasteboard_service",
|
||||
"acls": [
|
||||
"ohos.permission.INPUT_MONITORING",
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.GRANT_URI_PERMISSION_PRIVILEGED",
|
||||
"ohos.permission.GET_WIFI_INFO",
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "token_sync_service",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "deviceprofile",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "distributedfiledaemon",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "distributeddata",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.GRANT_URI_PERMISSION_PRIVILEGED"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "dhardware",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.SYNC_PROFILE_DP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "netmanager",
|
||||
"acls": [
|
||||
"ohos.permission.MANAGE_WIFI_HOTSPOT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "samgr",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.MANAGE_SYSTEM_ABILITY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "resource_schedule_service",
|
||||
"acls": [
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION",
|
||||
"ohos.permission.MANAGE_RGM",
|
||||
"ohos.permission.FILTER_INPUT_EVENT",
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER",
|
||||
"ohos.permission.GET_PAGE_INFO",
|
||||
"ohos.permission.ACCESS_EXT_SYSTEM_ABILITY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "el5_filekey_manager",
|
||||
"acls": [
|
||||
"ohos.permission.MONITOR_DEVICE_NETWORK_STATE",
|
||||
"ohos.permission.STORAGE_MANAGER_CRYPT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "security_guard",
|
||||
"acls": [
|
||||
"ohos.permission.COLLECT_SECURITY_EVENT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "telephony",
|
||||
"acls": [
|
||||
"ohos.permission.MANAGE_WIFI_CONNECTION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "netsysnative",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_USER_TRUSTED_CERT",
|
||||
"ohos.permission.ACCESS_SYSTEM_APP_CERT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "storage_daemon",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_SCREEN_LOCK_INNER"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "storage_manager",
|
||||
"acls": [
|
||||
"ohos.permission.ACCESS_SCREEN_LOCK_INNER"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "testserver",
|
||||
"acls": [
|
||||
"ohos.permission.DUMP",
|
||||
"ohos.permission.MANAGE_MISSIONS",
|
||||
"ohos.permission.CONNECT_IME_ABILITY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "device_manager",
|
||||
"acls": [
|
||||
"ohos.permission.MANAGE_SOFTBUS_NETWORK",
|
||||
"ohos.permission.ACCESS_DEVAUTH_CRED_PRIVILEGE",
|
||||
"ohos.permission.ACCESS_IDS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "hiprofiler_plugins",
|
||||
"acls": [
|
||||
"ohos.permission.HIVIEW_TRACE_MANAGE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "mechbody",
|
||||
"acls": [
|
||||
"ohos.permission.INJECT_INPUT_EVENT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "huks_service",
|
||||
"acls": [
|
||||
"ohos.permission.START_INVISIBLE_ABILITY",
|
||||
"ohos.permission.CONNECT_CRYPTO_EXTENSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "updater_sa",
|
||||
"acls": [
|
||||
"ohos.permission.STORAGE_MANAGER_CRYPT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "selection_service",
|
||||
"acls": [
|
||||
"ohos.permission.INPUT_MONITORING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "telecom",
|
||||
"acls": [
|
||||
"ohos.permission.SET_SUPER_PRIVACY",
|
||||
"ohos.permission.START_INVISIBLE_ABILITY",
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER"
|
||||
]
|
||||
},
|
||||
{
|
||||
"processName": "bgtaskmgr_service",
|
||||
"acls": [
|
||||
"ohos.permission.NOTIFICATION_CONTROLLER"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,98 @@
|
||||
[
|
||||
{
|
||||
"bundle&processName": "com.ohos.launcher",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "com.ohos.settings",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "com.ohos.systemui",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "com.ohos.screenlock",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "com.ohos.adminprovisioning",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "edm",
|
||||
"apl": "3"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "com.ohos.settings.faceauth",
|
||||
"apl": "2"
|
||||
},
|
||||
{
|
||||
"bundle&processName": "cn.openharmony.inputmethodchoosedialog",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"media_service",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.amsdialog",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.useriam.authwidget",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.powerdialog",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.filepicker",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.camera",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.smartperf",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.devicemanagerui",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"ohos.telephony.resources",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.notificationdialog",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"ohos.samples.distributedcalc",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"ohos.samples.distributedmusicplayer",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.note",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.devicetest",
|
||||
"apl":"2"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"com.ohos.screenshot",
|
||||
"apl":"3"
|
||||
},
|
||||
{
|
||||
"bundle&processName":"powermgr",
|
||||
"apl":"3"
|
||||
}
|
||||
]
|
||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 261 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 67 KiB |
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"case_file": "testcases/test_launcher.py",
|
||||
"description": "开机测试"
|
||||
},
|
||||
{
|
||||
"case_file": "testcases/test_process.py",
|
||||
"description": "进程检查"
|
||||
},
|
||||
{
|
||||
"case_file": "testcases/test_apl_check.py",
|
||||
"description": "外部用例APL白名单检查"
|
||||
},
|
||||
{
|
||||
"case_file": "testcases/test_acl_check.py",
|
||||
"description": "外部用例ACL白名单检查"
|
||||
},
|
||||
{
|
||||
"case_file": "testcases/test_crash_check.py",
|
||||
"description": "crash检查"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,157 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import pytest
|
||||
import sqlite3
|
||||
|
||||
|
||||
class Test:
|
||||
@pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
t = time.time()
|
||||
|
||||
check_list_file = os.path.join(device.resource_path, 'acl_whitelist.json')
|
||||
assert os.path.exists(check_list_file), '{} not exist'.format(check_list_file)
|
||||
logging.info('reading {} content'.format(check_list_file))
|
||||
whitelist_dict = {}
|
||||
json_data = json.load(open(check_list_file, 'r'))
|
||||
for item in json_data:
|
||||
whitelist_dict.update({item.get('processName'): item.get('acls')})
|
||||
|
||||
logging.info('exporting access_token.db')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db-wal')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db-shm')
|
||||
db_file = os.path.join(device.report_path, 'access_token.db')
|
||||
assert os.path.exists(db_file), '{} not exist'.format(db_file)
|
||||
|
||||
logging.info('exporting permission_definitions.json')
|
||||
DEFINE_PERMISSION_FILE = "/system/etc/access_token/permission_definitions.json"
|
||||
device.hdc_file_recv(DEFINE_PERMISSION_FILE)
|
||||
perm_def_file = os.path.join(device.report_path, 'permission_definitions.json')
|
||||
assert os.path.exists(perm_def_file), '{} not exist'.format(perm_def_file)
|
||||
|
||||
logging.info('exporting nativetoken.json')
|
||||
SA_INFO_FILE = "/data/service/el0/access_token/nativetoken.json"
|
||||
device.hdc_file_recv(SA_INFO_FILE)
|
||||
sa_info_file = os.path.join(device.report_path, 'nativetoken.json')
|
||||
assert os.path.exists(sa_info_file), '{} not exist'.format(sa_info_file)
|
||||
|
||||
logging.info('insert permission_definition_table')
|
||||
self.insert_perm(perm_def_file, db_file)
|
||||
|
||||
logging.info('querying native_token_info_table')
|
||||
|
||||
sa_result = self.query_sa_info(db_file, sa_info_file)
|
||||
assert sa_result, 'native_token_info_table is empty'
|
||||
|
||||
logging.info('querying from native_token_info_table end')
|
||||
|
||||
check_rst = True
|
||||
for process, permission_list in sa_result.items():
|
||||
if process not in whitelist_dict.keys():
|
||||
check_rst = False
|
||||
logging.error('processName={} not configured while list permission: {}'.format(process, permission_list))
|
||||
else:
|
||||
whitelist_set = set(whitelist_dict[process])
|
||||
permission_set = set(permission_list)
|
||||
not_applied = permission_set.difference(whitelist_set)
|
||||
if not_applied:
|
||||
check_rst = False
|
||||
logging.error('processName={} not configured while list permission: {}'.format(process, not_applied))
|
||||
|
||||
logging.info("ACL CHECK COST: {}s".format(time.time() - t))
|
||||
assert check_rst, 'ACL check failed'
|
||||
|
||||
@staticmethod
|
||||
def query_sa_info(db_file, sa_info_file):
|
||||
sql = 'SELECT permission_name, available_level FROM permission_definition_table;'
|
||||
conn = sqlite3.connect(db_file)
|
||||
assert conn, 'sqlit database connect failed'
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(sql)
|
||||
results = cursor.fetchall()
|
||||
conn.close()
|
||||
|
||||
perm_map ={}
|
||||
for item in results:
|
||||
permission_name = item[0]
|
||||
apl = item[1]
|
||||
perm_map[permission_name] = apl
|
||||
|
||||
check_pass = True
|
||||
result_map ={}
|
||||
|
||||
with open(sa_info_file, 'r') as file:
|
||||
data = json.load(file)
|
||||
for item in data:
|
||||
processName = item.get('processName')
|
||||
APL = item.get('APL')
|
||||
if APL == 3:
|
||||
logging.info('{} APL = 3, PASS.'.format(processName))
|
||||
continue
|
||||
|
||||
permissions = item.get('permissions')
|
||||
|
||||
if not permissions:
|
||||
logging.info('Process {} does not apply for permission, PASS.'.format(processName))
|
||||
continue
|
||||
|
||||
nativeAcls = item.get('nativeAcls')
|
||||
for perm in permissions:
|
||||
if perm in nativeAcls:
|
||||
continue
|
||||
|
||||
PAPL = perm_map.get(perm)
|
||||
if not PAPL:
|
||||
logging.warning('{} no definition'.format(perm))
|
||||
continue
|
||||
if PAPL > APL:
|
||||
logging.error('{} invalid is detected in {}'.format(perm, processName))
|
||||
check_pass = False
|
||||
|
||||
if nativeAcls:
|
||||
result_map[processName] = nativeAcls
|
||||
|
||||
assert check_pass, 'ACL check failed'
|
||||
return result_map
|
||||
|
||||
@staticmethod
|
||||
def insert_perm(perm_def_file, db_file):
|
||||
query_perm_sql = "select permission_name from permission_definition_table;"
|
||||
conn = sqlite3.connect(db_file)
|
||||
assert conn, 'sqlit database connect failed'
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(query_perm_sql)
|
||||
perms_list = cursor.fetchall()
|
||||
conn.close()
|
||||
perms_set = set()
|
||||
for perms in perms_list:
|
||||
perms_set.add(perms[0])
|
||||
|
||||
sql = 'insert into permission_definition_table(token_id, permission_name, bundle_name, grant_mode, available_level, provision_enable, distributed_scene_enable, label, label_id, description, description_id, available_type) values(560, ?, "xxxx", 1, ?, 1, 1, "xxxx", 1, "xxxx", 1, 1)'
|
||||
sql_data = []
|
||||
with open(perm_def_file, 'r') as file:
|
||||
data = json.load(file)
|
||||
perm_def_list = data.get('definePermissions')
|
||||
for item in perm_def_list:
|
||||
key = item.get('name')
|
||||
if key not in perms_set:
|
||||
value_str = item.get('availableLevel')
|
||||
value = 1
|
||||
if value_str == "system_core":
|
||||
value = 3
|
||||
elif value_str == "system_basic":
|
||||
value = 2
|
||||
sql_data.append([key, value])
|
||||
|
||||
logging.warning('insert permission_definition_table size: {}'.format(len(sql_data)))
|
||||
conn = sqlite3.connect(db_file)
|
||||
assert conn, 'sqlit database connect failed'
|
||||
cursor = conn.cursor()
|
||||
cursor.executemany(sql, sql_data)
|
||||
results = cursor.fetchall()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import json
|
||||
import math
|
||||
import os.path
|
||||
import sqlite3
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class Test:
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
#return
|
||||
check_list_file = os.path.join(device.resource_path, 'apl_check_list.json')
|
||||
logging.info('reading {}'.format(check_list_file))
|
||||
json_data = json.load(open(check_list_file, 'r'))
|
||||
whitelist_dict = {}
|
||||
for data in json_data:
|
||||
whitelist_dict.update({data.get('bundle&processName'): int(data.get('apl'))})
|
||||
assert whitelist_dict, 'check list is empty'
|
||||
|
||||
logging.info('exporting access_token.db')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db-wal')
|
||||
device.hdc_file_recv('/data/service/el1/public/access_token/access_token.db-shm')
|
||||
db_file = os.path.join(device.report_path, 'access_token.db')
|
||||
assert os.path.exists(db_file), '{} not exist'.format(db_file)
|
||||
|
||||
logging.info('exporting nativetoken.json')
|
||||
SA_INFO_FILE = "/data/service/el0/access_token/nativetoken.json"
|
||||
device.hdc_file_recv(SA_INFO_FILE)
|
||||
sa_info_file = os.path.join(device.report_path, 'nativetoken.json')
|
||||
assert os.path.exists(sa_info_file), '{} not exist'.format(sa_info_file)
|
||||
|
||||
logging.info('querying from hap_token_info_table')
|
||||
hap_apl_result = self.query_records(db_file, 'select bundle_name,apl from hap_token_info_table')
|
||||
assert hap_apl_result, 'hap_token_info_table is empty'
|
||||
logging.info('querying native_token_info_table')
|
||||
native_apl_result = self.get_sa_info(sa_info_file)
|
||||
assert native_apl_result, 'native_token_info_table is empty'
|
||||
|
||||
logging.info('hap apl checking')
|
||||
hap_check_rst = self.compare_db_with_whitelist(hap_apl_result, whitelist_dict, 1)
|
||||
logging.info('native apl checking')
|
||||
native_check_rst = self.compare_db_with_whitelist(native_apl_result, whitelist_dict, 2)
|
||||
assert hap_check_rst, 'hap apl check failed'
|
||||
assert native_check_rst, 'native apl check failed'
|
||||
|
||||
@staticmethod
|
||||
def get_sa_info(sa_info_file):
|
||||
result_dict = {}
|
||||
with open(sa_info_file, 'r') as file:
|
||||
data = json.load(file)
|
||||
for item in data:
|
||||
processName = item.get('processName')
|
||||
APL = item.get('APL')
|
||||
result_dict.update({processName: APL})
|
||||
return result_dict
|
||||
|
||||
@staticmethod
|
||||
def query_records(db_file, sql):
|
||||
conn = sqlite3.connect(db_file)
|
||||
assert conn, 'sqlit database connect failed'
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(sql)
|
||||
results = cursor.fetchall()
|
||||
conn.close()
|
||||
if not results:
|
||||
return
|
||||
result_dict = {}
|
||||
for line in results:
|
||||
key = line[0]
|
||||
value = 0 if math.isnan(line[1]) else line[1]
|
||||
result_dict.update({key: value})
|
||||
return result_dict
|
||||
|
||||
@staticmethod
|
||||
def compare_db_with_whitelist(db_data: dict, whitelist_dict: dict, basic_value):
|
||||
"""
|
||||
数据库和白名单对比
|
||||
:param db_data:
|
||||
:param whitelist_dict:
|
||||
:param basic_value:
|
||||
:return:
|
||||
"""
|
||||
check_rst = True
|
||||
for key, apl in db_data.items():
|
||||
if key not in whitelist_dict.keys():
|
||||
continue
|
||||
if apl <= basic_value:
|
||||
continue
|
||||
is_pass = whitelist_dict[key] == apl
|
||||
if not is_pass:
|
||||
logging.info('bundleName/processName = {} apl = {} | check failed'.format(key, apl))
|
||||
check_rst = False
|
||||
else:
|
||||
logging.info('bundleName/processName = {} apl = {} | check pass'.format(key, apl))
|
||||
return check_rst
|
||||
@@ -0,0 +1,46 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class Test:
|
||||
camera_ability_name = 'com.ohos.camera.MainAbility'
|
||||
camera_bundle_name = 'com.ohos.camera'
|
||||
photo_ability_name = 'com.ohos.photos.MainAbility'
|
||||
photo_bundle_name = 'com.ohos.photos'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [camera_bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start camera app')
|
||||
device.start_ability(self.camera_bundle_name, self.camera_ability_name)
|
||||
device.save_snapshot_to_local('{}_camera_step1.jpeg'.format(device.sn))
|
||||
|
||||
logging.info('click shot button')
|
||||
device.click(600, 1741)
|
||||
time.sleep(2)
|
||||
device.save_snapshot_to_local('{}_camera_step2.jpeg'.format(device.sn))
|
||||
|
||||
logging.info('switch to record mode')
|
||||
device.refresh_layout()
|
||||
confirm_element = device.get_element_by_text('录像')
|
||||
if confirm_element:
|
||||
device.click_element(confirm_element)
|
||||
time.sleep(2)
|
||||
device.save_snapshot_to_local('{}_camera_step3.jpeg'.format(device.sn))
|
||||
|
||||
logging.info('click shot button')
|
||||
device.click(600, 1741)
|
||||
time.sleep(5)
|
||||
device.save_snapshot_to_local('{}_camera_step4.jpeg'.format(device.sn))
|
||||
|
||||
logging.info('stop recoding')
|
||||
device.click(561, 1741)
|
||||
time.sleep(3)
|
||||
device.save_snapshot_to_local('{}_camera_step5.jpeg'.format(device.sn))
|
||||
|
||||
logging.info('click left behind button in order to switch to gallery app')
|
||||
device.click(437, 1740)
|
||||
time.sleep(5)
|
||||
device.save_snapshot_to_local('{}_camera_step6.jpeg'.format(device.sn))
|
||||
device.assert_process_running(self.photo_bundle_name)
|
||||
@@ -0,0 +1,30 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'com.ohos.contacts.MainAbility'
|
||||
bundle_name = 'com.ohos.contacts'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start contacts app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
time.sleep(5)
|
||||
|
||||
# 权限允许弹窗
|
||||
device.refresh_layout()
|
||||
confirm_element = device.get_element_by_text('允许')
|
||||
if confirm_element:
|
||||
device.click_element(confirm_element)
|
||||
time.sleep(2)
|
||||
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'contacts.jpeg')
|
||||
contacts_page_pic = device.save_snapshot_to_local('{}_contacts.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(contacts_page_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
@@ -0,0 +1,27 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('pull down controller center')
|
||||
start_x = int(device.width * 0.9)
|
||||
start_y = int(device.height * 0.01)
|
||||
end_x = start_x
|
||||
end_y = int(device.height * 0.15)
|
||||
device.swipe(from_x=start_x, from_y=start_y, to_x=end_x, to_y=end_y)
|
||||
time.sleep(2)
|
||||
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'controller_center.jpeg')
|
||||
controller_page_pic = device.save_snapshot_to_local('{}_controller_center.jpeg'.format(device.sn))
|
||||
|
||||
similarity = compare_image_similarity(controller_page_pic, standard_pic)
|
||||
device.dirc_fling(3)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
@@ -0,0 +1,13 @@
|
||||
import pytest
|
||||
import logging
|
||||
|
||||
class Test:
|
||||
|
||||
# @pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, device):
|
||||
crashes = device.hdc_shell('cd /data/log/faultlog/temp && grep "Process name" -rnw ./')
|
||||
if 'foundation' in crashes:
|
||||
logging.info('foundation crash check failed!')
|
||||
#assert 'foundation' not in crashes, 'foundation crash exist'
|
||||
assert 'render_service' not in crashes, 'render_service crash exist'
|
||||
assert 'appspawn' not in crashes, 'appspawn crash exist'
|
||||
@@ -0,0 +1,32 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'ohos.samples.distributedmusicplayer.MainAbility'
|
||||
bundle_name = 'ohos.samples.distributedmusicplayer'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start music app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
device.save_snapshot_to_local('{}_music_step1.jpeg'.format(device.sn))
|
||||
# 弹窗
|
||||
device.click(504, 708)
|
||||
device.stop_permission()
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'distributedmusicplayer.jpeg')
|
||||
music_page_pic = device.save_snapshot_to_local('{}_distributedmusicplayer.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(music_page_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
|
||||
# logging.info('音乐界面控件检查')
|
||||
# device.refresh_layout()
|
||||
# device.assert_key_exist('image1')
|
||||
# device.assert_key_exist('image2')
|
||||
# device.assert_key_exist('image3')
|
||||
# device.assert_key_exist('image4')
|
||||
@@ -0,0 +1,43 @@
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from utils.images import compare_image_similarity
|
||||
|
||||
|
||||
class Test:
|
||||
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('compare image similarity')
|
||||
# usb弹窗
|
||||
device.unlock()
|
||||
time.sleep(2)
|
||||
device.refresh_layout()
|
||||
confirm_element = device.get_element_by_text('确定')
|
||||
if confirm_element:
|
||||
device.click_element(confirm_element)
|
||||
time.sleep(2)
|
||||
|
||||
#time.sleep(10)
|
||||
#device.click(360, 1245)
|
||||
#device.unlock()
|
||||
#time.sleep(2)
|
||||
|
||||
#if device.get_focus_window() == 'SystemDialog1':
|
||||
# device.click(595, 555)
|
||||
# time.sleep(10)
|
||||
#if device.get_focus_window() == 'SystemDialog1':
|
||||
# device.click(360, 800)
|
||||
# time.sleep(10)
|
||||
standard_pic = os.path.join(device.resource_path, 'launcher.jpeg')
|
||||
launcher_pic = device.save_snapshot_to_local('{}_launcher.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(launcher_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
|
||||
# logging.info('检查桌面图标控件是否存在')
|
||||
# device.refresh_layout()
|
||||
# device.assert_type_exist('Badge')
|
||||
@@ -0,0 +1,26 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'com.ohos.mms.MainAbility'
|
||||
bundle_name = 'com.ohos.mms'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start mms app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'mms.jpeg')
|
||||
mms_page_pic = device.save_snapshot_to_local('{}_mms.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(mms_page_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
|
||||
# logging.info('信息界面控件检查')
|
||||
# device.refresh_layout()
|
||||
# device.assert_text_exist('信息')
|
||||
@@ -0,0 +1,38 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'MainAbility'
|
||||
bundle_name = 'com.ohos.note'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start note app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
# 截取笔记主页面
|
||||
device.save_snapshot_to_local('{}_note_mainpage.jpeg'.format(device.sn))
|
||||
|
||||
# 点击左侧笔记进入内容页
|
||||
logging.info('click note bookmark')
|
||||
device.click(242, 367)
|
||||
time.sleep(4)
|
||||
logging.info('click note content area')
|
||||
device.refresh_layout()
|
||||
for i in range(5):
|
||||
device.click(360, 325)
|
||||
time.sleep(2)
|
||||
device.click(360, 324)
|
||||
time.sleep(3)
|
||||
if device.is_soft_keyboard_on():
|
||||
break
|
||||
time.sleep(3)
|
||||
standard_pic = os.path.join(device.resource_path, 'note.jpeg')
|
||||
note_pic = device.save_snapshot_to_local('{}_note.jpeg'.format(device.sn))
|
||||
logging.info('compare image similarity')
|
||||
similarity = compare_image_similarity(note_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
@@ -0,0 +1,32 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'com.ohos.photos.MainAbility'
|
||||
bundle_name = 'com.ohos.photos'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start gallery app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'photos.jpeg')
|
||||
photos_page_pic = device.save_snapshot_to_local('{}_photos.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(photos_page_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
|
||||
logging.info('medialibrarydata process check')
|
||||
process = 'com.ohos.medialibrary.medialibrarydata'
|
||||
device.assert_process_running(process)
|
||||
time.sleep(1)
|
||||
|
||||
logging.info('sandbox path check')
|
||||
pid = device.get_pid(process)
|
||||
sanboxf = device.hdc_shell('echo \"ls /storage/media/local/\"|nsenter -t {} -m sh'.format(pid))
|
||||
assert 'files' in sanboxf, 'files not in {}'.format(sanboxf)
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2026 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 logging
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class Test:
|
||||
pid_list = [
|
||||
'com.ohos.launcher',
|
||||
'render_service',
|
||||
]
|
||||
|
||||
ps_list = [
|
||||
'hdf_devmgr',
|
||||
'param_watcher',
|
||||
'storage_manager',
|
||||
'appspawn',
|
||||
'hilogd',
|
||||
'samgr',
|
||||
'storage_daemon',
|
||||
'uinput_inject',
|
||||
'multimodalinput',
|
||||
'huks_service',
|
||||
'memmgrservice',
|
||||
'bluetooth_servi',
|
||||
'resource_schedu',
|
||||
'audio_server',
|
||||
'softbus_server',
|
||||
'faultloggerd',
|
||||
'accountmgr',
|
||||
'time_service',
|
||||
'distributeddata',
|
||||
'useriam',
|
||||
'inputmethod_ser',
|
||||
'ui_service',
|
||||
'netmanager',
|
||||
'sensors',
|
||||
'media_service',
|
||||
'wifi_manager_se',
|
||||
'installs',
|
||||
'hiview',
|
||||
'telephony',
|
||||
'camera_service',
|
||||
'foundation',
|
||||
'hdcd',
|
||||
'light_host',
|
||||
'vibrator_host',
|
||||
'sensor_host',
|
||||
'input_user_host',
|
||||
'camera_host',
|
||||
'audio_host',
|
||||
'wifi_host',
|
||||
'usb_host',
|
||||
'blue_host',
|
||||
'com.ohos.systemui',
|
||||
'power_host',
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [None], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
lost_process = []
|
||||
logging.info('check pid is exist or not')
|
||||
for process in self.pid_list:
|
||||
pid = device.get_pid(process)
|
||||
if not re.search(r'\d+', pid):
|
||||
lost_process.append(process)
|
||||
|
||||
ps_elf_rst = device.hdc_shell('ps -elf')
|
||||
for pname in self.ps_list:
|
||||
if pname not in ps_elf_rst:
|
||||
lost_process.append(pname)
|
||||
|
||||
logging.info('lost process are {}'.format(lost_process))
|
||||
assert not lost_process
|
||||
@@ -0,0 +1,44 @@
|
||||
import logging
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from utils.images import compare_image_similarity, crop_picture
|
||||
|
||||
|
||||
class Test:
|
||||
ability_name = 'com.ohos.settings.MainAbility'
|
||||
bundle_name = 'com.ohos.settings'
|
||||
|
||||
@pytest.mark.parametrize('setup_teardown', [bundle_name], indirect=True)
|
||||
def test(self, setup_teardown, device):
|
||||
logging.info('start setting app')
|
||||
device.start_ability(self.bundle_name, self.ability_name)
|
||||
|
||||
logging.info('compare image similarity')
|
||||
standard_pic = os.path.join(device.resource_path, 'settings.jpeg')
|
||||
settings_page_pic = device.save_snapshot_to_local('{}_settings.jpeg'.format(device.sn))
|
||||
similarity = compare_image_similarity(settings_page_pic, standard_pic)
|
||||
assert similarity > 0.5, 'compare similarity failed'
|
||||
|
||||
logging.info('enter wlan page')
|
||||
device.refresh_layout()
|
||||
wlan_element = device.get_element_by_text('WLAN')
|
||||
assert wlan_element, 'WLAN component not found'
|
||||
device.click_element(wlan_element)
|
||||
time.sleep(2)
|
||||
device.save_snapshot_to_local('{}_before_click.jpeg'.format(device.sn))
|
||||
before_click = device.get_wifi_status().get('active')
|
||||
|
||||
logging.info('turn on/off wlan swith')
|
||||
device.refresh_layout()
|
||||
wlan_switch = device.get_element_by_type('Toggle')
|
||||
assert wlan_switch, 'WLAN switch component not found'
|
||||
device.click_element(wlan_switch)
|
||||
time.sleep(8)
|
||||
|
||||
device.save_snapshot_to_local('{}_after_click.jpeg'.format(device.sn))
|
||||
after_click = device.get_wifi_status().get('active')
|
||||
logging.info('wlan switch changes from [{}] to [{}]'.format(before_click, after_click))
|
||||
assert before_click != after_click, 'wlan switch turn on/off failed'
|
||||
@@ -0,0 +1,611 @@
|
||||
import json
|
||||
import logging
|
||||
import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import threading
|
||||
|
||||
|
||||
class Device:
|
||||
lock = threading.Lock()
|
||||
|
||||
@classmethod
|
||||
def _execute_cmd(cls, cmd):
|
||||
with cls.lock:
|
||||
logging.info(f'[In]{cmd}')
|
||||
rst = subprocess.run(cmd, capture_output=True, shell=True, timeout=30, encoding='utf-8')
|
||||
out_put = rst.stdout or rst.stderr
|
||||
time.sleep(0.5)
|
||||
# 布局的回显太多了,不打印
|
||||
if not re.search(r'cat /data/local/tmp/\S+json', cmd):
|
||||
logging.info(f'[Out]{out_put}')
|
||||
return out_put
|
||||
|
||||
def __init__(self, sn):
|
||||
self.sn = sn
|
||||
self.report_path = ''
|
||||
self.resource_path = ''
|
||||
self.width = 720
|
||||
self.height = 1280
|
||||
self.velocity_range = (200, 40000)
|
||||
self._element_list = []
|
||||
self.get_render_size()
|
||||
|
||||
def hdc_shell(self, cmd):
|
||||
out = ''
|
||||
for i in range(3):
|
||||
shell_cmd = f'hdc -l0 -t {self.sn} shell "{cmd}"'
|
||||
out = self._execute_cmd(shell_cmd)
|
||||
if '[Fail]Device not founded or connected' in out:
|
||||
self.restart_hdc_process()
|
||||
time.sleep(5)
|
||||
else:
|
||||
break
|
||||
return out
|
||||
|
||||
def hdc(self, cmd):
|
||||
return self._execute_cmd(f'hdc -l0 -t {self.sn} {cmd}')
|
||||
|
||||
def hdc_version(self):
|
||||
return self._execute_cmd('hdc -v')
|
||||
|
||||
def hdc_list_targets(self):
|
||||
devices = self._execute_cmd('hdc list targets')
|
||||
if 'Empty' in devices:
|
||||
return []
|
||||
return devices.splitlines()
|
||||
|
||||
def install_hap(self, hap_path, replace=True):
|
||||
"""
|
||||
暗账应用
|
||||
:param hap_path: hap包的路径
|
||||
:param replace: 是否覆盖安装,true覆盖,否则不覆盖
|
||||
:return:
|
||||
"""
|
||||
logging.info('install hap')
|
||||
if replace:
|
||||
cmd = f'app install -r {hap_path}'
|
||||
else:
|
||||
cmd = f'app install {hap_path}'
|
||||
return self.hdc(cmd)
|
||||
|
||||
def install_multi_hap(self, hap_list: list):
|
||||
"""
|
||||
安装更新, 多hap可以指定多个文件路径
|
||||
:param hap_list:
|
||||
:return:
|
||||
"""
|
||||
logging.info('install hap')
|
||||
haps = ' '.join(hap_list)
|
||||
cmd = 'install {}'.format(haps)
|
||||
return self.hdc(cmd)
|
||||
|
||||
def bm_install(self, hap_list: list):
|
||||
"""
|
||||
bm工具安装更新多个hap
|
||||
:param hap_list:
|
||||
:return:
|
||||
"""
|
||||
logging.info('install hap')
|
||||
haps = ' '.join(hap_list)
|
||||
cmd = 'bm install -p {}'.format(haps)
|
||||
return self.hdc_shell(cmd)
|
||||
|
||||
def uninstall_hap(self, bundle_name):
|
||||
# 两个命令都可以
|
||||
logging.info(f'uninstall {bundle_name}')
|
||||
# cmd = 'hdc app uninstall {}'.format(bundle_name)
|
||||
return self.hdc(f'uninstall {bundle_name}')
|
||||
|
||||
def bm_uninstall(self, bundle_name):
|
||||
logging.info(f'uninstall {bundle_name}')
|
||||
return self.hdc_shell(f'bm uninstall -n {bundle_name}')
|
||||
|
||||
def hdc_file_send(self, local, remote):
|
||||
logging.info('send file to device')
|
||||
return self.hdc(f'file send "{local}" "{remote}"')
|
||||
|
||||
def hdc_file_recv(self, remote, local=''):
|
||||
logging.info('recv file from device')
|
||||
local = local or self.report_path
|
||||
return self.hdc(f'file recv "{remote}" "{local}"')
|
||||
|
||||
def hilog(self):
|
||||
logging.info('hilog')
|
||||
return self.hdc('hilog')
|
||||
|
||||
def get_udid(self):
|
||||
logging.info('get udid')
|
||||
return self.hdc('bm get --udid')
|
||||
|
||||
def kill_hdc_process(self):
|
||||
logging.info('kill hdc process')
|
||||
return self._execute_cmd('hdc kill')
|
||||
|
||||
def restart_hdc_process(self):
|
||||
# logging.info('restart hdc process')
|
||||
return self._execute_cmd('hdc start -r')
|
||||
|
||||
def reboot(self):
|
||||
# logging.info('reboot device')
|
||||
return self.hdc_shell('reboot')
|
||||
|
||||
def start_ability(self, bundle_name, ability_name):
|
||||
# logging.info(f'start {bundle_name} application')
|
||||
rst = self.hdc_shell(f'aa start -b {bundle_name} -a {ability_name}')
|
||||
time.sleep(2)
|
||||
return rst
|
||||
|
||||
def force_stop(self, bundle_name):
|
||||
# logging.info(f'停掉{bundle_name}应用')
|
||||
return self.hdc_shell(f'aa force-stop {bundle_name}')
|
||||
|
||||
def clean_app_data(self, bundle_name):
|
||||
"""
|
||||
清除应用缓存和数据, -c缓存, -d应用数据
|
||||
:param bundle_name:
|
||||
:return:
|
||||
"""
|
||||
if not bundle_name:
|
||||
return
|
||||
# logging.info(f'清理{bundle_name}应用数据和缓存')
|
||||
return self.hdc_shell(f'bm clean -n {bundle_name} -c -d')
|
||||
|
||||
def disable_app(self, bundle_name):
|
||||
"""
|
||||
禁止应用,应用在桌面消失
|
||||
:param bundle_name:
|
||||
:return:
|
||||
"""
|
||||
# logging.info(f'禁止{bundle_name}应用,应用在桌面消失')
|
||||
return self.hdc_shell(f'bm disable -n {bundle_name}')
|
||||
|
||||
def enable_app(self, bundle_name):
|
||||
"""
|
||||
允许应用,应用显示在桌面上
|
||||
:param bundle_name:
|
||||
:return:
|
||||
"""
|
||||
# logging.info(f'允许{bundle_name}应用,应用显示在桌面上')
|
||||
return self.hdc_shell(f'bm enable -n {bundle_name}')
|
||||
|
||||
def dump_hap_configuration(self, bundle_name):
|
||||
"""
|
||||
查看应用配置信息
|
||||
:param bundle_name:
|
||||
:return:
|
||||
"""
|
||||
# logging.info(f'查看{bundle_name}应用配置信息')
|
||||
return self.hdc_shell(f'bm dump -n {bundle_name}')
|
||||
|
||||
def stop_permission(self):
|
||||
# self.click(504, 708)
|
||||
# logging.info(f'消掉权限请求的弹窗')
|
||||
focus_win = self.get_focus_window()
|
||||
if 'permissionDialog1' in focus_win:
|
||||
# logging.info(f'消掉权限请求的弹窗')
|
||||
self.refresh_layout()
|
||||
allow = self.get_element_by_condition(condition={'text': '允许', 'type': 'Button'})
|
||||
self.click_element(allow)
|
||||
time.sleep(2)
|
||||
else:
|
||||
logging.info(f'current window: {focus_win}')
|
||||
# return self.force_stop('com.ohos.permissionmanager')
|
||||
|
||||
def click(self, x: int, y: int):
|
||||
"""
|
||||
模拟触摸按下
|
||||
:param x:
|
||||
:param y:
|
||||
:return:
|
||||
"""
|
||||
# logging.info(f'点击({x},{y})坐标')
|
||||
return self.hdc_shell(f'uinput -M -m {x} {y} -c 0')
|
||||
# return self.hdc_shell(f'uinput -T -c {x} {y}')
|
||||
# return self.hdc_shell(f'uitest uiInput click {x} {y}')
|
||||
|
||||
def click_element(self, e):
|
||||
x, y = self.center_of_element(e)
|
||||
return self.click(x, y)
|
||||
|
||||
def double_click(self, x, y):
|
||||
# logging.info(f'双击({x},{y})坐标')
|
||||
return self.hdc_shell(f'uitest uiInput doubleClick {x} {y}')
|
||||
|
||||
def double_click_element(self, e):
|
||||
x, y = self.center_of_element(e)
|
||||
return self.double_click(x, y)
|
||||
|
||||
def long_click(self, x, y):
|
||||
# logging.info(f'长按({x},{y})坐标')
|
||||
return self.hdc_shell(f'uitest uiInput longClick {x} {y}')
|
||||
|
||||
def long_click_element(self, e):
|
||||
x, y = self.center_of_element(e)
|
||||
return self.long_click(x, y)
|
||||
|
||||
def dirc_fling(self, direct=0):
|
||||
"""
|
||||
模拟指定方向滑动
|
||||
:param direct:direction (可选参数,滑动方向,可选值: [0,1,2,3], 滑动方向: [左,右,上,下],默认值: 0)
|
||||
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
|
||||
stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px)
|
||||
:return:
|
||||
"""
|
||||
direct_map = {
|
||||
0: '左',
|
||||
1: '右',
|
||||
2: '上',
|
||||
3: '下',
|
||||
}
|
||||
if direct not in direct_map.keys():
|
||||
direct = 0
|
||||
# logging.info(f'向 {direct_map.get(direct)} 滑动')
|
||||
return self.hdc_shell(f'uitest uiInput dircFling {direct}')
|
||||
|
||||
def swipe(self, from_x, from_y, to_x, to_y, velocity=600):
|
||||
"""
|
||||
模拟慢滑操作
|
||||
:param from_x:(必选参数,滑动起点x坐标)
|
||||
:param from_y:(必选参数,滑动起点y坐标)
|
||||
:param to_x:(必选参数,滑动终点x坐标)
|
||||
:param to_y:(必选参数,滑动终点y坐标)
|
||||
:param velocity: (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
|
||||
:return:
|
||||
"""
|
||||
# 保证数据取值范围合理
|
||||
# logging.info(f'从({from_x},{from_y})滑动到({to_x},{to_y}),滑动速度:{velocity}px/s')
|
||||
return self.hdc_shell(f'uitest uiInput swipe {from_x} {from_y} {to_x} {to_y} {velocity}')
|
||||
|
||||
def fling(self, from_x, from_y, to_x, to_y, velocity=600):
|
||||
"""
|
||||
模拟快滑操作
|
||||
:param from_x:(必选参数,滑动起点x坐标)
|
||||
:param from_y:(必选参数,滑动起点y坐标)
|
||||
:param to_x:(必选参数,滑动终点x坐标)
|
||||
:param to_y:(必选参数,滑动终点y坐标)
|
||||
:param velocity: (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
|
||||
:return:
|
||||
"""
|
||||
# 保证数据取值范围合理
|
||||
# 保证数据取值范围合理
|
||||
# logging.info(f'从({from_x},{from_y})快速滑动到({to_x},{to_y})')
|
||||
return self.hdc_shell(f'uitest uiInput fling {from_x} {from_y} {to_x} {to_y}')
|
||||
|
||||
def drag(self, from_x, from_y, to_x, to_y, velocity=600):
|
||||
"""
|
||||
拖拽,从(x1, y1)拖拽到(x2, y2)
|
||||
:param from_x:(必选参数,滑动起点x坐标)
|
||||
:param from_y:(必选参数,滑动起点y坐标)
|
||||
:param to_x:(必选参数,滑动终点x坐标)
|
||||
:param to_y:(必选参数,滑动终点y坐标)
|
||||
:param velocity: (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
|
||||
"""
|
||||
# logging.info(f'从({from_x},{from_y})拖到({to_x},{to_y}),拖动速度:{velocity}px/s')
|
||||
return self.hdc_shell(f'uitest uiInput drag {from_x} {from_y} {to_x} {to_y} {velocity}')
|
||||
|
||||
def key_event(self, key_code):
|
||||
# logging.info(f'按下{key_code}键')
|
||||
return self.hdc_shell(f'uitest uiInput keyEvent {key_code}')
|
||||
|
||||
def go_home(self):
|
||||
return self.key_event('Home')
|
||||
|
||||
def go_back(self):
|
||||
return self.key_event('Back')
|
||||
|
||||
def press_power_key(self):
|
||||
return self.key_event('Power')
|
||||
|
||||
def press_recent_key(self):
|
||||
return self.click(514, 1243)
|
||||
# return self.key_event('2078')
|
||||
|
||||
def clear_recent_task(self):
|
||||
# logging.info('清理最近的任务')
|
||||
self.press_recent_key()
|
||||
time.sleep(0.5)
|
||||
self.press_clear_btn()
|
||||
|
||||
def press_clear_btn(self):
|
||||
self.click(360, 1170)
|
||||
|
||||
def input_text(self, x, y, text=''):
|
||||
# logging.info(f'向({x, y})坐标处输入“{text}”')
|
||||
return self.hdc_shell(f'uitest uiInput inputText {x} {y} {text}')
|
||||
|
||||
def wakeup(self):
|
||||
# logging.info('点亮屏幕')
|
||||
return self.hdc_shell('power-shell wakeup')
|
||||
|
||||
def suspend(self):
|
||||
# logging.info('熄灭屏幕')
|
||||
return self.hdc_shell('power-shell suspend')
|
||||
|
||||
def set_power_mode(self, mode='602'):
|
||||
"""
|
||||
设置电源模式
|
||||
:param mode:600 normal mode 正常模式
|
||||
601 power save mode省电模式
|
||||
602 performance mode性能模式,屏幕会常亮
|
||||
603 extreme power save mode极端省电模式
|
||||
:return:
|
||||
"""
|
||||
power_map = {
|
||||
'600': '正常模式',
|
||||
'601': '省电模式',
|
||||
'602': '性能模式',
|
||||
'603': '极端省电模式',
|
||||
}
|
||||
if mode not in power_map.keys():
|
||||
mode = '602'
|
||||
# logging.info(f'设置电源为{power_map.get(mode)}')
|
||||
return self.hdc_shell(f'power-shell setmode {mode}')
|
||||
|
||||
def display_screen_state(self):
|
||||
# logging.info('获取屏幕点亮状态')
|
||||
return self.hdc_shell('hidumper -s 3308')
|
||||
|
||||
def get_render_size(self):
|
||||
# logging.info('获取屏幕分辨率')
|
||||
rst = self.hdc_shell('hidumper -s RenderService -a screen')
|
||||
# 适配不同格式的输出:render resolution=720x1280 或 render size: 720x1280
|
||||
xy = re.findall(r'render (?:resolution|size)[=:]\s*(\d+)x(\d+)', rst)[0]
|
||||
self.width, self.height = [int(i) for i in xy]
|
||||
# logging.info(f'屏幕分辨率: {self.width}x{self.height}')
|
||||
|
||||
def dump_layout(self, file_name=''):
|
||||
# logging.info('获取当前页面布局')
|
||||
if file_name:
|
||||
file_path = '/data/local/tmp/' + file_name
|
||||
dump_rst = self.hdc_shell(f'uitest dumpLayout -p {file_path}')
|
||||
else:
|
||||
dump_rst = self.hdc_shell(f'uitest dumpLayout')
|
||||
layout_file = dump_rst.split(':')[1].strip()
|
||||
return layout_file
|
||||
|
||||
def save_layout_to_local(self, file_name=''):
|
||||
layout_file = self.dump_layout(file_name)
|
||||
self.hdc_file_recv(layout_file)
|
||||
|
||||
def refresh_layout(self, file_name=''):
|
||||
"""
|
||||
:param file_name: 文件名不包含路径
|
||||
:return:
|
||||
"""
|
||||
file_name = file_name or 'tmp_layout.json'
|
||||
tmp_file = self.dump_layout(file_name)
|
||||
json_data = json.loads(self.hdc_shell(f'cat {tmp_file}'))
|
||||
self._element_list = self._parse_attribute_nodes(json_data)
|
||||
# 将控件按从上到下,从左到右的顺序排列
|
||||
self._element_list.sort(key=lambda e: [self.center_of_element(e)[1], self.center_of_element(e)[0]])
|
||||
|
||||
def snapshot_display(self, jpeg=''):
|
||||
"""jpeg必须在/data/local/tmp目录"""
|
||||
# logging.info('获取当前页面截图')
|
||||
if jpeg:
|
||||
jpeg = '/data/local/tmp/' + jpeg
|
||||
shot_rst = self.hdc_shell(f'snapshot_display -f {jpeg}')
|
||||
else:
|
||||
shot_rst = self.hdc_shell('snapshot_display')
|
||||
if 'success' not in shot_rst:
|
||||
return ''
|
||||
return re.findall(r'write to(.*)as jpeg', shot_rst)[0].strip()
|
||||
|
||||
def save_snapshot_to_local(self, file_name=''):
|
||||
from utils.images import crop_picture
|
||||
|
||||
tmp_file = self.snapshot_display(file_name)
|
||||
save_file = os.path.join(self.report_path, tmp_file.split('/')[-1])
|
||||
self.hdc_file_recv(tmp_file, self.report_path)
|
||||
|
||||
# 根据实际屏幕分辨率裁剪截图
|
||||
crop_picture(save_file, self.width, self.height)
|
||||
return save_file
|
||||
|
||||
def clear_local_tmp(self):
|
||||
self.hdc_shell('rm -rf /data/local/tmp/*')
|
||||
|
||||
def set_screen_timeout(self, timeout=600):
|
||||
"""
|
||||
设置屏幕超时时间
|
||||
:param timeout: 单位s
|
||||
:return:
|
||||
"""
|
||||
# logging.info(f'设置屏幕{timeout}s无操作后休眠')
|
||||
return self.hdc_shell(f'power-shell timeout -o {timeout * 1000}')
|
||||
|
||||
def rm_faultlog(self):
|
||||
# logging.info('删除fault log')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/SERVICE_BLOCK*')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/appfreeze*')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/temp/cppcrash*')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/faultlogger/jscrash*')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/faultlogger/appfreeze*')
|
||||
self.hdc_shell('rm -f /data/log/faultlog/faultlogger/cppcrash*')
|
||||
|
||||
def start_hilog(self):
|
||||
# logging.info('开启hilog')
|
||||
self.hdc_shell('hilog -w stop;hilog -w clear')
|
||||
self.hdc_shell('hilog -r;hilog -b INFO;hilog -w start -l 10M -n 1000')
|
||||
|
||||
def stop_and_collect_hilog(self, local_dir=''):
|
||||
# logging.info('停止并收集hilog')
|
||||
self.hdc_shell('hilog -w stop')
|
||||
self.hdc_file_recv('/data/log/hilog/', local_dir)
|
||||
|
||||
def unlock(self):
|
||||
"""
|
||||
滑动解锁
|
||||
:return:
|
||||
"""
|
||||
# logging.info('解锁屏幕')
|
||||
return self.dirc_fling(2)
|
||||
|
||||
def assert_process_running(self, process):
|
||||
# logging.info(f'检查{process}进程是否存在')
|
||||
rst = self.hdc_shell(f'ps -ef | grep -w {process} | grep -v grep')
|
||||
assert process in rst, f'process {process} not exist'
|
||||
|
||||
def get_pid(self, process):
|
||||
# logging.info(f'获取{process}进程PID')
|
||||
return self.hdc_shell(f'pidof {process}').strip()
|
||||
|
||||
def get_wifi_status(self):
|
||||
# hidumper -ls查看所有hidumper服务
|
||||
# logging.info('获取wifi状态')
|
||||
status = self.hdc_shell('hidumper -s WifiDevice')
|
||||
active_state = re.findall(r'WiFi active state: (.*)', status)[0].strip()
|
||||
connection_status = re.findall(r'WiFi connection status: (.*)', status)[0].strip()
|
||||
|
||||
scan_status = self.hdc_shell('hidumper -s WifiScan')
|
||||
is_scan_running = re.findall(r'Is scan service running: (.*)', scan_status)[0].strip()
|
||||
return {
|
||||
'active': active_state,
|
||||
'connected': connection_status,
|
||||
'scanning': is_scan_running
|
||||
}
|
||||
|
||||
def dump_windows_manager_service(self):
|
||||
rst = self.hdc_shell("hidumper -s WindowManagerService -a '-a'")
|
||||
return rst
|
||||
|
||||
def get_focus_window(self):
|
||||
time.sleep(1)
|
||||
text = self.dump_windows_manager_service()
|
||||
focus_win = re.findall(r'Focus window: (\d+)', text)[0].strip()
|
||||
win_id_index = 3
|
||||
focus_window_name = ''
|
||||
for line in text.splitlines():
|
||||
if line.startswith('Focus window'):
|
||||
break
|
||||
wms = re.match(r'\S*\s*(\d+\s+){' + str(win_id_index) + '}', line)
|
||||
if wms:
|
||||
data = wms.group().strip().split()
|
||||
if data[win_id_index] == focus_win:
|
||||
focus_window_name = data[0]
|
||||
break
|
||||
# logging.info('当前聚焦的窗口为:{}'.format(focus_window_name))
|
||||
return focus_window_name
|
||||
|
||||
def get_win_id(self, window_name):
|
||||
text = self.dump_windows_manager_service()
|
||||
win = re.search(window_name + r'\s*(\d+\s+){3}', text)
|
||||
if not win:
|
||||
return
|
||||
win_id = win.group().split()[-1]
|
||||
return win_id
|
||||
|
||||
def get_navigationb_winid(self):
|
||||
return self.get_win_id('SystemUi_NavigationB')
|
||||
|
||||
def is_soft_keyboard_on(self):
|
||||
if self.soft_keyboard():
|
||||
return True
|
||||
return False
|
||||
|
||||
def soft_keyboard(self):
|
||||
text = self.dump_windows_manager_service()
|
||||
keyboard = re.search(r'softKeyboard1\s*(\d+\s+){8}\[\s+(\d+\s+){4}]', text)
|
||||
if not keyboard:
|
||||
return ''
|
||||
return keyboard.group()
|
||||
|
||||
def get_elements_by_text(self, text):
|
||||
ems = []
|
||||
for e in self._element_list:
|
||||
if e.get('text') == text:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_text(self, text, index=0):
|
||||
ems = self.get_elements_by_text(text)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_text_exist(self, text):
|
||||
element = self.get_elements_by_text(text)
|
||||
rst = 'Yes' if element else 'No'
|
||||
logging.info('check [text]="{}" exist? [{}]'.format(text, rst))
|
||||
assert element
|
||||
|
||||
def get_elements_by_type(self, _type):
|
||||
ems = []
|
||||
for e in self._element_list:
|
||||
if e.get('type') == _type:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_type(self, _type, index=0):
|
||||
ems = self.get_elements_by_type(_type)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_type_exist(self, _type):
|
||||
element = self.get_elements_by_type(_type)
|
||||
rst = 'Yes' if element else 'No'
|
||||
logging.info('check [type]="{}"exist? [{}]'.format(_type, rst))
|
||||
assert element
|
||||
|
||||
def get_elements_by_key(self, key):
|
||||
ems = []
|
||||
for e in self._element_list:
|
||||
if e.get('key') == key:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_key(self, key, index=0):
|
||||
ems = self.get_elements_by_key(key)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_key_exist(self, key):
|
||||
element = self.get_elements_by_key(key)
|
||||
rst = 'Yes' if element else 'No'
|
||||
logging.info('check [key]="{}"exist? [{}]'.format(key, rst))
|
||||
assert element
|
||||
|
||||
def get_elements_by_condition(self, condition: dict):
|
||||
ems = []
|
||||
for e in self._element_list:
|
||||
cs = set(condition.items())
|
||||
if cs.issubset(set(e.items())):
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_condition(self, condition, index=0):
|
||||
ems = self.get_elements_by_condition(condition)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def set_brightness(self, value=102):
|
||||
return self.hdc_shell(f'power-shell display -s {value}')
|
||||
|
||||
@staticmethod
|
||||
def center_of_element(e):
|
||||
assert e, 'element not exist'
|
||||
bounds = e.get('bounds')
|
||||
x1, y1, x2, y2 = [int(i) for i in re.findall(r'\d+', bounds)]
|
||||
x = (x1 + x2) // 2
|
||||
y = (y1 + y2) // 2
|
||||
return x, y
|
||||
|
||||
def _parse_attribute_nodes(self, json_obj, attr_list=None):
|
||||
if attr_list is None:
|
||||
attr_list = []
|
||||
|
||||
if isinstance(json_obj, dict):
|
||||
for key, value in json_obj.items():
|
||||
if key == 'attributes' and isinstance(value, dict):
|
||||
attr_list.append(value)
|
||||
elif isinstance(value, (dict, list)):
|
||||
self._parse_attribute_nodes(value, attr_list)
|
||||
elif isinstance(json_obj, list):
|
||||
for item in json_obj:
|
||||
self._parse_attribute_nodes(item, attr_list)
|
||||
return attr_list
|
||||
@@ -0,0 +1,63 @@
|
||||
import logging
|
||||
import os.path
|
||||
|
||||
import cv2
|
||||
|
||||
|
||||
def crop_picture(picture, width=720, height=1280):
|
||||
"""
|
||||
根据屏幕分辨率裁剪图片,去除状态栏
|
||||
:param picture: 图片路径
|
||||
:param width: 屏幕宽度
|
||||
:param height: 屏幕高度
|
||||
"""
|
||||
img = cv2.imread(picture)
|
||||
if img is None:
|
||||
return
|
||||
|
||||
img_height, img_width = img.shape[:2]
|
||||
|
||||
# 顶部状态栏、底部导航栏需要去除的高度
|
||||
status_bar_height = 120
|
||||
navigation_bar_height = 1800
|
||||
|
||||
# 裁剪去除状态栏,保留完整屏幕内容
|
||||
x1, y1 = 0, status_bar_height
|
||||
x2, y2 = img_width, navigation_bar_height
|
||||
|
||||
img = img[y1:y2, x1:x2]
|
||||
cv2.imwrite(picture, img)
|
||||
|
||||
|
||||
def compare_image_similarity(image1, image2):
|
||||
logging.info('{} is exist? [{}]'.format(image1, os.path.exists(image1)))
|
||||
logging.info('{} is exist? [{}]'.format(image2, os.path.exists(image2)))
|
||||
if not os.path.exists(image1) or not os.path.exists(image2):
|
||||
logging.info('file not found, set similarity as 0%')
|
||||
return 0
|
||||
image1 = cv2.imread(image1, 0)
|
||||
image2 = cv2.imread(image2, 0)
|
||||
|
||||
# 初始化特征点检测器和描述符
|
||||
orb = cv2.ORB_create(edgeThreshold=5, patchSize=30)
|
||||
keypoints1, descriptors1 = orb.detectAndCompute(image1, None)
|
||||
keypoints2, descriptors2 = orb.detectAndCompute(image2, None)
|
||||
|
||||
# 初始化匹配器
|
||||
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
|
||||
|
||||
# 匹配特征点
|
||||
matches = bf.match(descriptors1, descriptors2)
|
||||
if not matches:
|
||||
logging.info('no fixture point found, set similarity as 0%')
|
||||
return 0
|
||||
if not keypoints1:
|
||||
if not keypoints2:
|
||||
logging.info('similarity is 100%')
|
||||
return 1
|
||||
logging.info('similarity is 0%')
|
||||
return 0
|
||||
# 计算相似度
|
||||
similarity = len(matches) / len(keypoints1)
|
||||
logging.info('similarity is {}%'.format(similarity * 100))
|
||||
return similarity
|
||||
@@ -0,0 +1,89 @@
|
||||
import logging
|
||||
import re
|
||||
|
||||
|
||||
class Layout:
|
||||
|
||||
def __init__(self, json_data):
|
||||
self.element_list = self.parse_attribute_nodes(json_data)
|
||||
|
||||
def parse_attribute_nodes(self, json_obj, attr_list=None):
|
||||
if attr_list is None:
|
||||
attr_list = []
|
||||
|
||||
if isinstance(json_obj, dict):
|
||||
for key, value in json_obj.items():
|
||||
if key == 'attributes' and isinstance(value, dict):
|
||||
attr_list.append(value)
|
||||
elif isinstance(value, (dict, list)):
|
||||
self.parse_attribute_nodes(value, attr_list)
|
||||
elif isinstance(json_obj, list):
|
||||
for item in json_obj:
|
||||
self.parse_attribute_nodes(item, attr_list)
|
||||
return attr_list
|
||||
|
||||
def get_elements_by_text(self, text):
|
||||
ems = []
|
||||
for e in self.element_list:
|
||||
if e.get('text') == text:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_text(self, text, index=0):
|
||||
ems = self.get_elements_by_text(text)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_text_exist(self, text):
|
||||
element = self.get_elements_by_text(text)
|
||||
rst = '是' if element else '否'
|
||||
logging.info('检查[文本]="{}"是否存在?[{}]'.format(text, rst))
|
||||
assert element
|
||||
|
||||
def get_elements_by_type(self, _type):
|
||||
ems = []
|
||||
for e in self.element_list:
|
||||
if e.get('type') == _type:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_type(self, _type, index=0):
|
||||
ems = self.get_elements_by_type(_type)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_type_exist(self, _type):
|
||||
element = self.get_elements_by_type(_type)
|
||||
rst = '是' if element else '否'
|
||||
logging.info('检查[type]="{}"是否存在?[{}]'.format(_type, rst))
|
||||
assert element
|
||||
|
||||
def get_elements_by_key(self, key):
|
||||
ems = []
|
||||
for e in self.element_list:
|
||||
if e.get('key') == key:
|
||||
ems.append(e)
|
||||
return ems
|
||||
|
||||
def get_element_by_key(self, key, index=0):
|
||||
ems = self.get_elements_by_key(key)
|
||||
if not ems:
|
||||
return
|
||||
return ems[index]
|
||||
|
||||
def assert_key_exist(self, key):
|
||||
element = self.get_elements_by_key(key)
|
||||
rst = '是' if element else '否'
|
||||
logging.info('检查[key]="{}"是否存在?[{}]'.format(key, rst))
|
||||
assert element
|
||||
|
||||
@staticmethod
|
||||
def center_of_element(e):
|
||||
assert e, '控件不存在'
|
||||
bounds = e.get('bounds')
|
||||
x1, y1, x2, y2 = [int(i) for i in re.findall(r'\d+', bounds)]
|
||||
x = (x1 + x2) // 2
|
||||
y = (y1 + y2) // 2
|
||||
return x, y
|
||||