303 lines
14 KiB
Python
303 lines
14 KiB
Python
import logging
|
||
import os
|
||
import time
|
||
import subprocess
|
||
from tkinter import E
|
||
from appium import webdriver
|
||
from appium.options.android import UiAutomator2Options
|
||
from appium.webdriver.common.appiumby import AppiumBy
|
||
from selenium.webdriver.support.ui import WebDriverWait
|
||
from selenium.webdriver.support import expected_conditions as EC
|
||
from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
||
from page_objects.download_tabbar_page import DownloadTabbarPage
|
||
from page_objects.measure_tabbar_page import MeasureTabbarPage
|
||
from page_objects.section_mileage_config_page import SectionMileageConfigPage
|
||
from page_objects.upload_config_page import UploadConfigPage
|
||
from page_objects.more_download_page import MoreDownloadPage
|
||
from page_objects.screenshot_page import ScreenshotPage
|
||
import globals.driver_utils as driver_utils # 导入驱动工具模块
|
||
import globals.global_variable as global_variable
|
||
from page_objects.login_page import LoginPage
|
||
import globals.apis as apis
|
||
import globals.create_link as create_link
|
||
|
||
|
||
class DeviceAutomation:
|
||
def __init__(self, device_id=None):
|
||
# 如果没有提供设备ID,则自动获取
|
||
if device_id is None:
|
||
self.device_id = self.get_device_id()
|
||
else:
|
||
self.device_id = device_id
|
||
|
||
# 初始化权限
|
||
if driver_utils.grant_appium_permissions(self.device_id):
|
||
logging.info(f"设备 {self.device_id} 授予Appium权限成功")
|
||
else:
|
||
logging.warning(f"设备 {self.device_id} 授予Appium权限失败")
|
||
|
||
# 确保Appium服务器正在运行,不在运行则启动
|
||
if not driver_utils.check_server_status(4723):
|
||
driver_utils.start_appium_server()
|
||
|
||
# 初始化Appium驱动和页面对象
|
||
self.init_driver()
|
||
# 创建测试结果目录
|
||
self.results_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_results')
|
||
|
||
@staticmethod
|
||
def get_device_id() -> str:
|
||
"""
|
||
获取设备ID,优先使用已连接设备,否则使用全局配置
|
||
"""
|
||
try:
|
||
# 检查已连接设备
|
||
result = subprocess.run(
|
||
["adb", "devices"],
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=10
|
||
)
|
||
|
||
# # 解析设备列表
|
||
# for line in result.stdout.strip().split('\n')[1:]:
|
||
# if line.strip() and "device" in line and "offline" not in line:
|
||
# device_id = line.split('\t')[0]
|
||
# logging.info(f"使用已连接设备: {device_id}")
|
||
# global_variable.GLOBAL_DEVICE_ID = device_id
|
||
# return device_id
|
||
|
||
target_port = "4723"
|
||
for line in result.stdout.strip().split('\n')[1:]:
|
||
if line.strip() and "device" in line and "offline" not in line:
|
||
device_id = line.split('\t')[0]
|
||
|
||
# 检查是否为无线设备且端口为4723
|
||
if ':' in device_id:
|
||
ip_port = device_id.split(':')
|
||
if len(ip_port) == 2 and ip_port[1] == target_port:
|
||
logging.info(f"找到目标无线设备(端口{target_port}): {device_id}")
|
||
global_variable.GLOBAL_DEVICE_ID = device_id
|
||
return device_id
|
||
|
||
# 如果没有找到端口4723的设备,找其他无线设备
|
||
for line in result.stdout.strip().split('\n')[1:]:
|
||
if line.strip() and "device" in line and "offline" not in line:
|
||
device_id = line.split('\t')[0]
|
||
|
||
# 检查是否为无线设备(任何端口)
|
||
if ':' in device_id and device_id.split(':')[-1].isdigit():
|
||
logging.info(f"未找到端口{target_port}的设备,使用其他无线设备: {device_id}")
|
||
global_variable.GLOBAL_DEVICE_ID = device_id
|
||
return device_id
|
||
|
||
# 如果没有任何无线设备,找有线设备
|
||
for line in result.stdout.strip().split('\n')[1:]:
|
||
if line.strip() and "device" in line and "offline" not in line:
|
||
device_id = line.split('\t')[0]
|
||
logging.info(f"未找到无线设备,使用有线设备: {device_id}")
|
||
global_variable.GLOBAL_DEVICE_ID = device_id
|
||
return device_id
|
||
|
||
logging.error("未找到任何可用设备")
|
||
return None
|
||
|
||
except Exception as e:
|
||
logging.warning(f"设备检测失败: {e}")
|
||
|
||
# 使用全局配置
|
||
device_id = global_variable.GLOBAL_DEVICE_ID
|
||
logging.info(f"使用全局配置设备: {device_id}")
|
||
return device_id
|
||
|
||
|
||
def init_driver(self):
|
||
"""初始化Appium驱动"""
|
||
try:
|
||
# 使用全局函数初始化驱动
|
||
self.driver, self.wait = driver_utils.init_appium_driver(self.device_id)
|
||
# 初始化页面对象
|
||
logging.info(f"设备 {self.device_id} 开始初始化页面对象")
|
||
self.login_page = LoginPage(self.driver, self.wait)
|
||
self.download_tabbar_page = DownloadTabbarPage(self.driver, self.wait, self.device_id)
|
||
self.measure_tabbar_page = MeasureTabbarPage(self.driver, self.wait,self.device_id)
|
||
self.section_mileage_config_page = SectionMileageConfigPage(self.driver, self.wait, self.device_id)
|
||
self.upload_config_page = UploadConfigPage(self.driver, self.wait, self.device_id)
|
||
self.more_download_page = MoreDownloadPage(self.driver, self.wait,self.device_id)
|
||
self.screenshot_page = ScreenshotPage(self.driver, self.wait, self.device_id)
|
||
logging.info(f"设备 {self.device_id} 所有页面对象初始化完成")
|
||
|
||
# 检查应用是否成功启动
|
||
if driver_utils.is_app_launched(self.driver):
|
||
logging.info(f"设备 {self.device_id} 沉降观测App已成功启动")
|
||
else:
|
||
logging.warning(f"设备 {self.device_id} 应用可能未正确启动(init_driver)")
|
||
driver_utils.launch_app_manually(self.driver)
|
||
|
||
except Exception as e:
|
||
logging.error(f"设备 {self.device_id} 初始化驱动失败: {str(e)}")
|
||
raise
|
||
|
||
def run_automation(self):
|
||
"""根据当前应用状态处理相应的操作"""
|
||
try:
|
||
max_retry = 3 # 限制最大重试次数
|
||
retry_count = 0
|
||
while retry_count < max_retry:
|
||
login_btn_exists = self.login_page.is_login_page()
|
||
if not login_btn_exists:
|
||
logging.error(f"设备 {self.device_id} 未知应用状态,无法确定当前页面,跳转到登录页面")
|
||
if self.login_page.navigate_to_login_page(self.driver, self.device_id):
|
||
logging.info(f"设备 {self.device_id} 成功跳转到登录页面")
|
||
else:
|
||
logging.error(f"设备 {self.device_id} 跳转到登录页面失败")
|
||
retry_count += 1
|
||
continue
|
||
# 处理登录页面状态
|
||
logging.info(f"设备 {self.device_id} 检测到登录页面,执行登录操作")
|
||
max_retries_login = 3
|
||
login_success = False
|
||
|
||
for attempt in range(max_retries_login + 1):
|
||
if self.login_page.login("wangshun"):
|
||
login_success = True
|
||
break
|
||
else:
|
||
if attempt < max_retries_login:
|
||
logging.warning(f"设备 {self.device_id} 登录失败,准备重试 ({attempt + 1}/{max_retries_login})")
|
||
time.sleep(2) # 等待2秒后重试
|
||
else:
|
||
logging.error(f"设备 {self.device_id} 登录失败,已达到最大重试次数")
|
||
|
||
if login_success:
|
||
break
|
||
elif retry_count == max_retry-1:
|
||
logging.error(f"设备 {self.device_id} 处理登录页面失败,已达到最大重试次数")
|
||
return False
|
||
else:
|
||
retry_count += 1
|
||
|
||
# login_btn_exists = self.login_page.is_login_page()
|
||
# if not login_btn_exists:
|
||
# logging.error(f"设备 {self.device_id} 未知应用状态,无法确定当前页面,跳转到登录页面")
|
||
# if self.login_page.navigate_to_login_page(self.driver, self.device_id):
|
||
# logging.info(f"设备 {self.device_id} 成功跳转到登录页面")
|
||
# return self.run_automation() # 递归调用处理登录后的状态
|
||
# else:
|
||
# logging.error(f"设备 {self.device_id} 跳转到登录页面失败")
|
||
# return False
|
||
|
||
# # 处理登录页面状态
|
||
# logging.info(f"设备 {self.device_id} 检测到登录页面,执行登录操作")
|
||
# max_retries = 1
|
||
# login_success = False
|
||
|
||
# for attempt in range(max_retries + 1):
|
||
# if self.login_page.login():
|
||
# login_success = True
|
||
# break
|
||
# else:
|
||
# if attempt < max_retries:
|
||
# logging.warning(f"设备 {self.device_id} 登录失败,准备重试 ({attempt + 1}/{max_retries})")
|
||
# time.sleep(2) # 等待2秒后重试
|
||
# else:
|
||
# logging.error(f"设备 {self.device_id} 登录失败,已达到最大重试次数")
|
||
|
||
# if not login_success:
|
||
# return False
|
||
|
||
logging.info(f"设备 {self.device_id} 登录成功,继续执行更新操作")
|
||
time.sleep(1)
|
||
|
||
|
||
# 执行更新操作
|
||
if not self.download_tabbar_page.download_tabbar_page_manager():
|
||
logging.error(f"设备 {self.device_id} 更新操作执行失败")
|
||
return False
|
||
|
||
task_count = 0
|
||
max_tasks = 1 # 最大任务数量,防止无限循环
|
||
|
||
while task_count < max_tasks:
|
||
# 获取测量任务
|
||
logging.info(f"设备 {self.device_id} 获取测量任务 (第{task_count + 1}次)")
|
||
# task_data = apis.get_measurement_task()
|
||
# logging.info(f"设备 {self.device_id} 获取到的测量任务: {task_data}")
|
||
task_data = {
|
||
"id": 39,
|
||
"user_name": "czsczq115ykl",
|
||
"name": "czsczq115ykl",
|
||
"line_num": "L179451",
|
||
"line_name": "CDWZQ-2标-资阳沱江特大桥-23-35-山区",
|
||
"remaining": "0",
|
||
"status": 1
|
||
}
|
||
if not task_data:
|
||
logging.info(f"设备 {self.device_id} 未获取到状态为1的测量任务,等待后重试")
|
||
time.sleep(1) # 等待1秒后重试
|
||
break
|
||
# continue
|
||
|
||
# 设置全局变量
|
||
global_variable.GLOBAL_CURRENT_PROJECT_NAME = task_data.get('line_name', '')
|
||
global_variable.GLOBAL_LINE_NUM = task_data.get('line_num', '')
|
||
logging.info(f"设备 {self.device_id} 当前要处理的项目名称:{global_variable.GLOBAL_CURRENT_PROJECT_NAME}")
|
||
|
||
# 执行测量操作
|
||
# logging.info(f"设备 {self.device_id} 开始执行测量操作")
|
||
if not self.measure_tabbar_page.measure_tabbar_page_manager():
|
||
logging.error(f"设备 {self.device_id} 测量操作执行失败")
|
||
|
||
# # 返回到测量页面
|
||
# self.driver.back()
|
||
# self.check_and_click_confirm_popup_appium()
|
||
|
||
continue # 继续下一个任务
|
||
|
||
logging.info(f"设备 {self.device_id} 测量页面操作执行成功")
|
||
|
||
# 在测量操作完成后执行断面里程配置
|
||
logging.info(f"设备 {self.device_id} 开始执行断面里程配置")
|
||
if not self.section_mileage_config_page.section_mileage_config_page_manager():
|
||
logging.error(f"设备 {self.device_id} 断面里程配置执行失败")
|
||
continue # 继续下一个任务
|
||
|
||
# 任务完成后短暂等待
|
||
logging.info(f"设备 {self.device_id} 第{task_count}个任务完成")
|
||
task_count += 1
|
||
|
||
logging.info(f"设备 {self.device_id} 已完成{task_count}个任务,结束打数据流程")
|
||
if task_count == 0:
|
||
logging.error(f"没有完成打数据的线路,结束任务")
|
||
return False
|
||
|
||
|
||
# GLOBAL_TESTED_BREAKPOINT_LIST 把已打完的写入日志文件
|
||
with open(os.path.join(self.results_dir, "打数据完成线路.txt"), "w", encoding='utf-8') as f:
|
||
for bp in global_variable.GLOBAL_TESTED_BREAKPOINT_LIST:
|
||
f.write(f"{bp}\n")
|
||
|
||
return task_count > 0
|
||
|
||
except Exception as e:
|
||
logging.error(f"设备 {self.device_id} 处理应用状态时出错: {str(e)}")
|
||
return False
|
||
|
||
# 主执行逻辑
|
||
if __name__ == "__main__":
|
||
create_link.setup_adb_wireless()
|
||
automation = None
|
||
try:
|
||
automation = DeviceAutomation()
|
||
success = automation.run_automation()
|
||
|
||
if success:
|
||
logging.info(f"设备 {automation.device_id} 自动化流程执行成功")
|
||
else:
|
||
logging.error(f"设备 {automation.device_id} 自动化流程执行失败")
|
||
except Exception as e:
|
||
logging.error(f"设备执行出错: {str(e)}")
|
||
finally:
|
||
if automation:
|
||
driver_utils.safe_quit_driver(automation.driver, automation.device_id)
|