diff --git a/plugins/sonic-appium-uiautomator2-server-test.apk b/plugins/sonic-appium-uiautomator2-server-test.apk index 81879526..40fbcd38 100644 Binary files a/plugins/sonic-appium-uiautomator2-server-test.apk and b/plugins/sonic-appium-uiautomator2-server-test.apk differ diff --git a/plugins/sonic-appium-uiautomator2-server.apk b/plugins/sonic-appium-uiautomator2-server.apk index e4dd668f..0afb318e 100644 Binary files a/plugins/sonic-appium-uiautomator2-server.apk and b/plugins/sonic-appium-uiautomator2-server.apk differ diff --git a/plugins/sonic-ios-bridge.exe b/plugins/sonic-ios-bridge.exe index 4ae03f13..67a4e24c 100644 Binary files a/plugins/sonic-ios-bridge.exe and b/plugins/sonic-ios-bridge.exe differ diff --git a/pom.xml b/pom.xml index 2af60a27..59526207 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ io.github.soniccloudorg sonic-driver-core - 1.1.7 + 1.1.9 @@ -93,7 +93,7 @@ org.jsoup jsoup - 1.11.3 + 1.15.3 io.github.soniccloudorg diff --git a/src/main/java/org/cloud/sonic/agent/automation/AndroidStepHandler.java b/src/main/java/org/cloud/sonic/agent/automation/AndroidStepHandler.java index 21f157ff..8435eb73 100644 --- a/src/main/java/org/cloud/sonic/agent/automation/AndroidStepHandler.java +++ b/src/main/java/org/cloud/sonic/agent/automation/AndroidStepHandler.java @@ -19,9 +19,6 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.android.ddmlib.IDevice; -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.PumpStreamHandler; import org.cloud.sonic.agent.bridge.android.AndroidDeviceBridgeTool; import org.cloud.sonic.agent.bridge.android.AndroidDeviceThreadPool; import org.cloud.sonic.agent.common.enums.AndroidKey; @@ -39,6 +36,7 @@ import org.cloud.sonic.agent.tests.script.GroovyScriptImpl; import org.cloud.sonic.agent.tools.BytesTool; import org.cloud.sonic.agent.tools.PortTool; +import org.cloud.sonic.agent.tools.ProcessCommandTool; import org.cloud.sonic.agent.tools.SpringTool; import org.cloud.sonic.agent.tools.file.DownloadTool; import org.cloud.sonic.agent.tools.file.UploadTools; @@ -49,6 +47,7 @@ import org.cloud.sonic.driver.common.tool.SonicRespException; import org.cloud.sonic.driver.poco.PocoDriver; import org.cloud.sonic.driver.poco.enums.PocoEngine; +import org.cloud.sonic.driver.poco.enums.PocoSelector; import org.cloud.sonic.driver.poco.models.PocoElement; import org.cloud.sonic.vision.cv.AKAZEFinder; import org.cloud.sonic.vision.cv.SIFTFinder; @@ -63,10 +62,8 @@ import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriverService; import org.openqa.selenium.chrome.ChromeOptions; -import org.testng.Assert; import javax.imageio.stream.FileImageOutputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.util.*; @@ -116,15 +113,26 @@ public void setGlobalParams(JSONObject jsonObject) { */ public void startAndroidDriver(IDevice iDevice, int uiaPort) throws Exception { this.iDevice = iDevice; - try { - androidDriver = new AndroidDriver("http://127.0.0.1:" + uiaPort); - androidDriver.disableLog(); - log.sendStepLog(StepType.PASS, "连接设备驱动成功", ""); - } catch (Exception e) { - log.sendStepLog(StepType.ERROR, "连接设备驱动失败!", ""); + int retry = 0; + Exception out = null; + while (retry <= 4) { + try { + androidDriver = new AndroidDriver("http://127.0.0.1:" + uiaPort); + break; + } catch (Exception e) { + log.sendStepLog(StepType.WARN, String.format("连接 UIAutomator2 Server 失败!重试第 %d 次...", retry + 1), ""); + out = e; + } + retry++; + Thread.sleep(2000); + } + if (androidDriver == null) { + log.sendStepLog(StepType.ERROR, "连接 UIAutomator2 Server 失败!", ""); setResultDetailStatus(ResultDetailStatus.FAIL); - throw e; + throw out; } + androidDriver.disableLog(); + log.sendStepLog(StepType.PASS, "连接 UIAutomator2 Server 成功", ""); log.androidInfo("Android", iDevice.getProperty(IDevice.PROP_BUILD_VERSION), iDevice.getSerialNumber(), iDevice.getProperty(IDevice.PROP_DEVICE_MANUFACTURER), iDevice.getProperty(IDevice.PROP_DEVICE_MODEL), @@ -1216,20 +1224,41 @@ public void startPocoDriver(HandleDes handleDes, String engine, int port) { pocoDriver = new PocoDriver(PocoEngine.valueOf(engine), pocoPort); } - public PocoElement findPocoEle(String expression) throws SonicRespException { - return pocoDriver.findElement(expression); + public PocoElement findPocoEle(String selector, String pathValue) throws Throwable { + PocoElement pocoElement = null; + pathValue = TextHandler.replaceTrans(pathValue, globalParams); + pocoDriver.getPageSourceForXmlElement(); + try { + switch (selector) { + case "poco": + pocoElement = pocoDriver.findElement(PocoSelector.POCO, pathValue); + break; + case "xpath": + pocoElement = pocoDriver.findElement(PocoSelector.XPATH, pathValue); + break; + case "cssSelector": + pocoElement = pocoDriver.findElement(PocoSelector.CSS_SELECTOR, pathValue); + break; + default: + log.sendStepLog(StepType.ERROR, "查找控件元素失败", "这个控件元素类型: " + selector + " 不存在!!!"); + break; + } + } catch (Throwable e) { + throw e; + } + return pocoElement; } - public void isExistPocoEle(HandleDes handleDes, String des, String value, boolean expect) { + public void isExistPocoEle(HandleDes handleDes, String des, String selector, String value, boolean expect) { handleDes.setStepDes("判断控件 " + des + " 是否存在"); handleDes.setDetail("期望值:" + (expect ? "存在" : "不存在")); boolean hasEle = false; try { - PocoElement w = findPocoEle(value); + PocoElement w = findPocoEle(selector, value); if (w != null) { hasEle = true; } - } catch (Exception e) { + } catch (Throwable e) { } try { assertEquals(hasEle, expect); @@ -1238,11 +1267,11 @@ public void isExistPocoEle(HandleDes handleDes, String des, String value, boolea } } - public void pocoClick(HandleDes handleDes, String des, String value) { + public void pocoClick(HandleDes handleDes, String des, String selector, String value) { handleDes.setStepDes("点击" + des); handleDes.setDetail("点击 " + value); try { - PocoElement w = findPocoEle(value); + PocoElement w = findPocoEle(selector, value); if (w != null) { List pos = w.getPayload().getPos(); int[] realCoordinates = getTheRealCoordinatesOfPoco(pos.get(0), pos.get(1)); @@ -1250,16 +1279,16 @@ public void pocoClick(HandleDes handleDes, String des, String value) { } else { throw new SonicRespException(value + " not found!"); } - } catch (Exception e) { + } catch (Throwable e) { handleDes.setE(e); } } - public void pocoLongPress(HandleDes handleDes, String des, String value, int time) { + public void pocoLongPress(HandleDes handleDes, String des, String selector, String value, int time) { handleDes.setStepDes("长按" + des); handleDes.setDetail("长按 " + value); try { - PocoElement w = findPocoEle(value); + PocoElement w = findPocoEle(selector, value); if (w != null) { List pos = w.getPayload().getPos(); int[] realCoordinates = getTheRealCoordinatesOfPoco(pos.get(0), pos.get(1)); @@ -1267,17 +1296,17 @@ public void pocoLongPress(HandleDes handleDes, String des, String value, int tim } else { throw new SonicRespException(value + " not found!"); } - } catch (Exception e) { + } catch (Throwable e) { handleDes.setE(e); } } - public void pocoSwipe(HandleDes handleDes, String des, String value, String des2, String value2) { + public void pocoSwipe(HandleDes handleDes, String des, String selector, String value, String des2, String selector2, String value2) { handleDes.setStepDes("滑动拖拽" + des + "到" + des2); handleDes.setDetail("拖拽 " + value + " 到 " + value2); try { - PocoElement w1 = findPocoEle(value); - PocoElement w2 = findPocoEle(value2); + PocoElement w1 = findPocoEle(selector, value); + PocoElement w2 = findPocoEle(selector2, value2); if (w1 != null && w2 != null) { List pos1 = w1.getPayload().getPos(); int[] realCoordinates1 = getTheRealCoordinatesOfPoco(pos1.get(0), pos1.get(1)); @@ -1288,7 +1317,7 @@ public void pocoSwipe(HandleDes handleDes, String des, String value, String des2 } else { throw new SonicRespException(value + " or " + value2 + " not found!"); } - } catch (Exception e) { + } catch (Throwable e) { handleDes.setE(e); } } @@ -1578,29 +1607,16 @@ public void runScript(HandleDes handleDes, String script, String type) { break; case "Python": File temp = new File("test-output" + File.separator + UUID.randomUUID() + ".py"); - if (!temp.exists()) { - temp.createNewFile(); - FileWriter fileWriter = new FileWriter(temp); - fileWriter.write(script); - fileWriter.close(); - } - CommandLine cmdLine = new CommandLine(String.format("python %s", temp.getAbsolutePath())); - cmdLine.addArgument(androidDriver.getSessionId(), false); - cmdLine.addArgument(iDevice.getSerialNumber(), false); - cmdLine.addArgument(globalParams.toJSONString(), false); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); + temp.createNewFile(); + FileWriter fileWriter = new FileWriter(temp); + fileWriter.write(script); + fileWriter.close(); try { - DefaultExecutor executor = new DefaultExecutor(); - executor.setStreamHandler(streamHandler); - int exit = executor.execute(cmdLine); - log.sendStepLog(StepType.INFO, "", "Run result:
" + outputStream); - Assert.assertEquals(exit, 0); + String re = ProcessCommandTool.getProcessLocalCommandStr(String.format("python %s %s %s %s", temp.getAbsolutePath(), androidDriver.getSessionId(), iDevice.getSerialNumber(), globalParams.toJSONString())); + log.sendStepLog(StepType.INFO, "", "Run result:
" + re); } catch (Exception e) { handleDes.setE(e); } finally { - outputStream.close(); - streamHandler.stop(); temp.delete(); } break; @@ -1789,20 +1805,21 @@ public void runStep(JSONObject stepJSON, HandleDes handleDes) throws Throwable { startPocoDriver(handleDes, step.getString("content"), step.getInteger("text")); break; case "isExistPocoEle": - isExistPocoEle(handleDes, eleList.getJSONObject(0).getString("eleName") + isExistPocoEle(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleType") , eleList.getJSONObject(0).getString("eleValue"), step.getBoolean("content")); break; case "pocoClick": - pocoClick(handleDes, eleList.getJSONObject(0).getString("eleName") + pocoClick(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleType") , eleList.getJSONObject(0).getString("eleValue")); break; case "pocoLongPress": - pocoLongPress(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleValue") + pocoLongPress(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleType") + , eleList.getJSONObject(0).getString("eleValue") , Integer.parseInt(step.getString("content"))); break; case "pocoSwipe": - pocoSwipe(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleValue") - , eleList.getJSONObject(1).getString("eleName"), eleList.getJSONObject(1).getString("eleValue")); + pocoSwipe(handleDes, eleList.getJSONObject(0).getString("eleName"), eleList.getJSONObject(0).getString("eleType"), eleList.getJSONObject(0).getString("eleValue") + , eleList.getJSONObject(1).getString("eleName"), eleList.getJSONObject(1).getString("eleType"), eleList.getJSONObject(1).getString("eleValue")); break; case "setTheRealPositionOfTheWindow": setTheRealPositionOfTheWindow(handleDes, step.getString("content")); diff --git a/src/main/java/org/cloud/sonic/agent/automation/IOSStepHandler.java b/src/main/java/org/cloud/sonic/agent/automation/IOSStepHandler.java index f4edbdb0..ff7d74ca 100644 --- a/src/main/java/org/cloud/sonic/agent/automation/IOSStepHandler.java +++ b/src/main/java/org/cloud/sonic/agent/automation/IOSStepHandler.java @@ -18,9 +18,6 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.PumpStreamHandler; import org.cloud.sonic.agent.bridge.ios.SibTool; import org.cloud.sonic.agent.common.enums.ConditionEnum; import org.cloud.sonic.agent.common.enums.SonicEnum; @@ -35,6 +32,7 @@ import org.cloud.sonic.agent.tests.handlers.StepHandlers; import org.cloud.sonic.agent.tests.script.GroovyScript; import org.cloud.sonic.agent.tests.script.GroovyScriptImpl; +import org.cloud.sonic.agent.tools.ProcessCommandTool; import org.cloud.sonic.agent.tools.SpringTool; import org.cloud.sonic.agent.tools.file.DownloadTool; import org.cloud.sonic.agent.tools.file.UploadTools; @@ -53,10 +51,8 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Attribute; import org.jsoup.nodes.Document; -import org.testng.Assert; import javax.imageio.stream.FileImageOutputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.nio.charset.StandardCharsets; @@ -100,9 +96,9 @@ public void startIOSDriver(String udId, int wdaPort) throws Exception { try { iosDriver = new IOSDriver("http://127.0.0.1:" + wdaPort); iosDriver.disableLog(); - log.sendStepLog(StepType.PASS, "连接设备驱动成功", ""); + log.sendStepLog(StepType.PASS, "连接 WebDriverAgent 成功", ""); } catch (Exception e) { - log.sendStepLog(StepType.ERROR, "连接设备驱动失败!", ""); + log.sendStepLog(StepType.ERROR, "连接 WebDriverAgent 失败!", ""); setResultDetailStatus(ResultDetailStatus.FAIL); throw e; } @@ -864,29 +860,16 @@ public void runScript(HandleDes handleDes, String script, String type) { break; case "Python": File temp = new File("test-output" + File.separator + UUID.randomUUID() + ".py"); - if (!temp.exists()) { - temp.createNewFile(); - FileWriter fileWriter = new FileWriter(temp); - fileWriter.write(script); - fileWriter.close(); - } - CommandLine cmdLine = new CommandLine(String.format("python %s", temp.getAbsolutePath())); - cmdLine.addArgument(iosDriver.getSessionId(), false); - cmdLine.addArgument(udId, false); - cmdLine.addArgument(globalParams.toJSONString(), false); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); + temp.createNewFile(); + FileWriter fileWriter = new FileWriter(temp); + fileWriter.write(script); + fileWriter.close(); try { - DefaultExecutor executor = new DefaultExecutor(); - executor.setStreamHandler(streamHandler); - int exit = executor.execute(cmdLine); - log.sendStepLog(StepType.INFO, "", "Run result:
" + outputStream); - Assert.assertEquals(exit, 0); + String re = ProcessCommandTool.getProcessLocalCommandStr(String.format("python %s %s %s %s", temp.getAbsolutePath(), iosDriver.getSessionId(), udId, globalParams.toJSONString())); + log.sendStepLog(StepType.INFO, "", "Run result:
" + re); } catch (Exception e) { handleDes.setE(e); } finally { - outputStream.close(); - streamHandler.stop(); temp.delete(); } break; diff --git a/src/main/java/org/cloud/sonic/agent/bridge/android/AndroidDeviceBridgeTool.java b/src/main/java/org/cloud/sonic/agent/bridge/android/AndroidDeviceBridgeTool.java index 6640a400..20fef347 100644 --- a/src/main/java/org/cloud/sonic/agent/bridge/android/AndroidDeviceBridgeTool.java +++ b/src/main/java/org/cloud/sonic/agent/bridge/android/AndroidDeviceBridgeTool.java @@ -491,7 +491,7 @@ public static int[] getDisplayOfAllScreen(IDevice iDevice, int width, int height Pattern pattern = Pattern.compile(patten); Matcher m = pattern.matcher(window); while (m.find()) { - if (m.groupCount()!=4)break; + if (m.groupCount() != 4) break; offsetx = Integer.parseInt(m.group(1)); offsety = Integer.parseInt(m.group(2)); width = Integer.parseInt(m.group(3)); @@ -513,7 +513,7 @@ public static int[] getDisplayOfAllScreen(IDevice iDevice, int width, int height } } } - return new int[]{offsetx, offsety,width,height}; + return new int[]{offsetx, offsety, width, height}; } public static String getCurrentPackage(IDevice iDevice) { @@ -679,6 +679,10 @@ true, new InstallReceiver(), 180L, 180L, TimeUnit.MINUTES iDevice.installPackage("plugins/sonic-appium-uiautomator2-server-test.apk", true, new InstallReceiver(), 180L, 180L, TimeUnit.MINUTES , "-r", "-t"); + executeCommand(iDevice, "appops set io.appium.uiautomator2.server RUN_IN_BACKGROUND allow"); + executeCommand(iDevice, "appops set io.appium.uiautomator2.server.test RUN_IN_BACKGROUND allow"); + executeCommand(iDevice, "dumpsys deviceidle whitelist +io.appium.uiautomator2.server"); + executeCommand(iDevice, "dumpsys deviceidle whitelist +io.appium.uiautomator2.server.test"); } int port = PortTool.getPort(); UiaThread uiaThread = new UiaThread(iDevice, port); @@ -686,7 +690,7 @@ true, new InstallReceiver(), 180L, 180L, TimeUnit.MINUTES int wait = 0; while (!uiaThread.getIsOpen()) { try { - Thread.sleep(500); + Thread.sleep(800); } catch (InterruptedException e) { e.printStackTrace(); } @@ -792,7 +796,7 @@ public static File getChromeDriver(IDevice iDevice, String packageName) throws I String major = chromeVersion.substring(0, end); HttpHeaders headers = new HttpHeaders(); ResponseEntity infoEntity = - restTemplate.exchange(String.format("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%d", major), HttpMethod.GET, new HttpEntity(headers), String.class); + restTemplate.exchange(String.format("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s", major), HttpMethod.GET, new HttpEntity(headers), String.class); if (system.contains("win")) { system = "win32"; } else if (system.contains("linux")) { @@ -800,7 +804,16 @@ public static File getChromeDriver(IDevice iDevice, String packageName) throws I } else { String arch = System.getProperty("os.arch").toLowerCase(); if (arch.contains("aarch64")) { - system = "mac64_m1"; + // fix m1 arm version obtained is lower than 87 for special processing + String driverList = restTemplate.exchange(String.format("https://registry.npmmirror.com/-/binary/chromedriver/%s/", infoEntity.getBody()), HttpMethod.GET, new HttpEntity(headers), String.class).getBody(); + for (Object obj : JSONArray.parseArray(driverList)) { + JSONObject jsonObject = JSONObject.parseObject(obj.toString()); + String fullName = jsonObject.getString("name"); + if (fullName.contains("m1") || fullName.contains("arm")) { + system = fullName.substring(fullName.indexOf("mac"), fullName.indexOf(".")); + break; + } + } } else { system = "mac64"; } diff --git a/src/main/java/org/cloud/sonic/agent/bridge/ios/SibTool.java b/src/main/java/org/cloud/sonic/agent/bridge/ios/SibTool.java index f915d26d..6c5894b1 100644 --- a/src/main/java/org/cloud/sonic/agent/bridge/ios/SibTool.java +++ b/src/main/java/org/cloud/sonic/agent/bridge/ios/SibTool.java @@ -158,7 +158,9 @@ public static List getDeviceList() { if (a.length() == 0) { break; } - result.add(a.substring(0, a.indexOf(" "))); + if (a.indexOf(" ") != -1) { + result.add(a.substring(0, a.indexOf(" "))); + } } return result; } diff --git a/src/main/java/org/cloud/sonic/agent/tests/AndroidTests.java b/src/main/java/org/cloud/sonic/agent/tests/AndroidTests.java index 7be11097..bf978a45 100644 --- a/src/main/java/org/cloud/sonic/agent/tests/AndroidTests.java +++ b/src/main/java/org/cloud/sonic/agent/tests/AndroidTests.java @@ -83,7 +83,8 @@ public void run(JSONObject jsonObject) throws IOException { // 启动任务 AndroidTestTaskBootThread bootThread = new AndroidTestTaskBootThread(jsonObject, androidStepHandler); - if (!runningTestsMap.containsKey(rid + "")) { + // runningTestsMap的key在rid的基础上再加上udid,避免分发到设备上的用例不均,先执行的完的用例remove rid,导致用例执行不完全的问题 + if (!runningTestsMap.containsKey(rid + "-" + udId)) { logger.info("任务【{}】中断,跳过", bootThread.getName()); return; } diff --git a/src/main/java/org/cloud/sonic/agent/tests/IOSTests.java b/src/main/java/org/cloud/sonic/agent/tests/IOSTests.java index 3b630c81..aa47a4e7 100644 --- a/src/main/java/org/cloud/sonic/agent/tests/IOSTests.java +++ b/src/main/java/org/cloud/sonic/agent/tests/IOSTests.java @@ -85,7 +85,8 @@ public void run(JSONObject jsonObject) throws IOException { // 启动任务 IOSTestTaskBootThread bootThread = new IOSTestTaskBootThread(jsonObject, iosStepHandler); - if (!runningTestsMap.containsKey(rid + "")) { + // runningTestsMap的key在rid的基础上再加上udid,避免先执行完的会remove rid,导致用例执行不完全的问题 + if (!runningTestsMap.containsKey(rid + "-" + udId)) { logger.info("任务【{}】中断,跳过", bootThread.getName()); return; } diff --git a/src/main/java/org/cloud/sonic/agent/tests/SuiteListener.java b/src/main/java/org/cloud/sonic/agent/tests/SuiteListener.java index b5c7a080..d93925c1 100644 --- a/src/main/java/org/cloud/sonic/agent/tests/SuiteListener.java +++ b/src/main/java/org/cloud/sonic/agent/tests/SuiteListener.java @@ -17,6 +17,9 @@ package org.cloud.sonic.agent.tests; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.util.CollectionUtils; import org.testng.ISuite; import org.testng.ISuiteListener; @@ -34,13 +37,38 @@ public class SuiteListener implements ISuiteListener { @Override public void onStart(ISuite suite) { - String rid = JSON.parseObject(suite.getParameter("dataInfo")).getString("rid"); - runningTestsMap.put(rid, true); + String runningTestsMapKey = getRunningTestsMapKey(suite); + if (runningTestsMapKey == null || runningTestsMapKey.length() == 0){ + return; + } + runningTestsMap.put(runningTestsMapKey, true); } @Override public void onFinish(ISuite suite) { - String rid = JSON.parseObject(suite.getParameter("dataInfo")).getString("rid"); - runningTestsMap.remove(rid); + String runningTestsMapKey = getRunningTestsMapKey(suite); + if (runningTestsMapKey == null || runningTestsMapKey.length() == 0){ + return; + } + // 加上udId,避免先完成的设备移除后,后完成的设备无法执行后续操作 + runningTestsMap.remove(runningTestsMapKey); + } + + private String getRunningTestsMapKey(ISuite suite){ + JSONObject dataInfoJson = JSON.parseObject(suite.getParameter("dataInfo")); + String rid = dataInfoJson.getString("rid"); + JSONArray deviceArray = dataInfoJson.getJSONArray("device"); + if (CollectionUtils.isEmpty(deviceArray)){ + return null; + } + JSONObject jsonObject = deviceArray.getJSONObject(0); + if (jsonObject == null){ + return null; + } + String udId = jsonObject.getString("udId"); + if (udId == null || udId.length() == 0){ + return null; + } + return rid + "-" + udId; } } diff --git a/src/main/java/org/cloud/sonic/agent/tests/TaskManager.java b/src/main/java/org/cloud/sonic/agent/tests/TaskManager.java index c0e76424..8a7ebe24 100644 --- a/src/main/java/org/cloud/sonic/agent/tests/TaskManager.java +++ b/src/main/java/org/cloud/sonic/agent/tests/TaskManager.java @@ -258,7 +258,7 @@ public static void forceStopSuite(int platform, int resultId, int caseId, String } } } - runningTestsMap.remove(resultId + ""); + runningTestsMap.remove(resultId + "-" + udId); runningRidSet.remove(resultId + "-" + udId); runningUdIdSet.remove(udId); diff --git a/src/main/java/org/cloud/sonic/agent/tests/ios/IOSRunStepThread.java b/src/main/java/org/cloud/sonic/agent/tests/ios/IOSRunStepThread.java index e33e5ccf..1bfda781 100644 --- a/src/main/java/org/cloud/sonic/agent/tests/ios/IOSRunStepThread.java +++ b/src/main/java/org/cloud/sonic/agent/tests/ios/IOSRunStepThread.java @@ -54,12 +54,14 @@ public void run() { JSONObject jsonObject = iosTestTaskBootThread.getJsonObject(); List steps = jsonObject.getJSONArray("steps").toJavaList(JSONObject.class); + // 复用同一个handleDes + HandleDes handleDes = new HandleDes(); for (JSONObject step : steps) { if (isStopped()) { return; } try { - stepHandlers.runStep(step, new HandleDes(), this); + stepHandlers.runStep(step, handleDes, this); } catch (Throwable e) { break; } diff --git a/src/main/java/org/cloud/sonic/agent/tools/file/FileTool.java b/src/main/java/org/cloud/sonic/agent/tools/file/FileTool.java index 69330dda..ecce0e9e 100644 --- a/src/main/java/org/cloud/sonic/agent/tools/file/FileTool.java +++ b/src/main/java/org/cloud/sonic/agent/tools/file/FileTool.java @@ -84,6 +84,8 @@ public static File unZipChromeDriver(File source, String version) { e.printStackTrace(); } if (driver != null) { + driver.setExecutable(true); + driver.setWritable(true); source.delete(); } return driver; diff --git a/src/main/java/org/cloud/sonic/agent/tools/file/UploadTools.java b/src/main/java/org/cloud/sonic/agent/tools/file/UploadTools.java index bce06a0b..cd605d9f 100644 --- a/src/main/java/org/cloud/sonic/agent/tools/file/UploadTools.java +++ b/src/main/java/org/cloud/sonic/agent/tools/file/UploadTools.java @@ -68,7 +68,12 @@ public static String upload(File uploadFile, String type) { ResponseEntity responseEntity = restTemplate.postForEntity(baseUrl + "/upload", param, JSONObject.class); if (responseEntity.getBody().getInteger("code") == 2000) { - transfer.delete(); + if (uploadFile.exists()) { + uploadFile.delete(); + } + if (transfer.exists()) { + transfer.delete(); + } } else { logger.info("发送失败!" + responseEntity.getBody()); } diff --git a/src/main/java/org/cloud/sonic/agent/websockets/AndroidTerminalWSServer.java b/src/main/java/org/cloud/sonic/agent/websockets/AndroidTerminalWSServer.java index 21dab9ea..cb8590a0 100644 --- a/src/main/java/org/cloud/sonic/agent/websockets/AndroidTerminalWSServer.java +++ b/src/main/java/org/cloud/sonic/agent/websockets/AndroidTerminalWSServer.java @@ -77,14 +77,14 @@ public void onOpen(Session session, @PathParam("key") String secretKey, udIdMap.put(session, iDevice); String username = iDevice.getProperty("ro.product.device"); Future terminal = AndroidDeviceThreadPool.cachedThreadPool.submit(() -> { - logger.info(udId + "开启terminal"); + logger.info(udId + "open terminal"); JSONObject ter = new JSONObject(); ter.put("msg", "terminal"); ter.put("user", username); BytesTool.sendText(session, ter.toJSONString()); }); Future logcat = AndroidDeviceThreadPool.cachedThreadPool.submit(() -> { - logger.info(udId + "开启logcat"); + logger.info(udId + "open logcat"); JSONObject ter = new JSONObject(); ter.put("msg", "logcat"); BytesTool.sendText(session, ter.toJSONString()); diff --git a/src/main/java/org/cloud/sonic/agent/websockets/AndroidWSServer.java b/src/main/java/org/cloud/sonic/agent/websockets/AndroidWSServer.java index 26ef4776..e863fb4e 100644 --- a/src/main/java/org/cloud/sonic/agent/websockets/AndroidWSServer.java +++ b/src/main/java/org/cloud/sonic/agent/websockets/AndroidWSServer.java @@ -59,7 +59,7 @@ import java.util.concurrent.TimeUnit; @Component -@ServerEndpoint(value = "/websockets/android/{key}/{udId}/{token}/{isAutoInit}", configurator = WsEndpointConfigure.class) +@ServerEndpoint(value = "/websockets/android/{key}/{udId}/{token}", configurator = WsEndpointConfigure.class) public class AndroidWSServer implements IAndroidWSServer { private final Logger logger = LoggerFactory.getLogger(AndroidWSServer.class); @@ -74,8 +74,8 @@ public class AndroidWSServer implements IAndroidWSServer { @OnOpen public void onOpen(Session session, @PathParam("key") String secretKey, - @PathParam("udId") String udId, @PathParam("token") String token, @PathParam("isAutoInit") Integer isAutoInit) throws Exception { - if (secretKey.length() == 0 || (!secretKey.equals(key)) || token.length() == 0 || isAutoInit == null) { + @PathParam("udId") String udId, @PathParam("token") String token) throws Exception { + if (secretKey.length() == 0 || (!secretKey.equals(key)) || token.length() == 0) { logger.info("拦截访问!"); return; } @@ -110,22 +110,24 @@ public void onOpen(Session session, @PathParam("key") String secretKey, .replaceAll("\n", "") .replaceAll("\t", ""); if (path.length() > 0 && AndroidDeviceBridgeTool.checkSonicApkVersion(iDevice)) { - logger.info("已安装Sonic插件,检查版本信息通过"); + logger.info("Check Sonic Apk version and status pass..."); } else { - logger.info("未安装Sonic插件或版本不是最新,正在安装..."); + logger.info("Sonic Apk version not newest or not install, starting install..."); try { iDevice.uninstallPackage("org.cloud.sonic.android"); } catch (InstallException e) { - logger.info("卸载出错..."); + logger.info("uninstall sonic Apk err..."); } try { iDevice.installPackage("plugins/sonic-android-apk.apk", true, new InstallReceiver(), 180L, 180L, TimeUnit.MINUTES , "-r", "-t", "-g"); - logger.info("Sonic插件安装完毕"); + AndroidDeviceBridgeTool.executeCommand(iDevice, "appops set org.cloud.sonic.android RUN_IN_BACKGROUND allow"); + AndroidDeviceBridgeTool.executeCommand(iDevice, "dumpsys deviceidle whitelist +org.cloud.sonic.android"); + logger.info("Sonic Apk install successful."); } catch (InstallException e) { e.printStackTrace(); - logger.info("Sonic插件安装失败!"); + logger.info("Sonic Apk install failed."); return; } path = AndroidDeviceBridgeTool.executeCommand(iDevice, "pm path org.cloud.sonic.android").trim() @@ -167,7 +169,7 @@ public boolean isCancelled() { } }, 0, TimeUnit.MILLISECONDS); } catch (Exception e) { - logger.info("{} 设备touch服务启动异常!" + logger.info("{} device touch service launch err" , iDevice.getSerialNumber()); logger.error(e.getMessage()); } @@ -240,9 +242,7 @@ public boolean isCancelled() { AndroidSupplyTool.startShare(udId, session); - if (isAutoInit == 1) { - openDriver(iDevice, session); - } + openDriver(iDevice, session); } @OnClose @@ -377,7 +377,7 @@ public void onMessage(String message, Session session) { androidStepHandler.startPocoDriver(new HandleDes(), msg.getString("engine"), msg.getInteger("port")); JSONObject poco = new JSONObject(); try { - poco.put("result", androidStepHandler.getPocoDriver().getPageSourceForJson()); + poco.put("result", androidStepHandler.getPocoDriver().getPageSourceForJsonString()); } catch (SonicRespException e) { poco.put("result", ""); e.printStackTrace(); @@ -495,7 +495,6 @@ public void onMessage(String message, Session session) { } case "eleScreen": { if (androidStepHandler != null && androidStepHandler.getAndroidDriver() != null) { - AndroidStepHandler finalAndroidStepHandler = androidStepHandler; AndroidDeviceThreadPool.cachedThreadPool.execute(() -> { JSONObject result = new JSONObject(); result.put("msg", "eleScreen"); @@ -528,28 +527,30 @@ public void onMessage(String message, Session session) { } private void openDriver(IDevice iDevice, Session session) { - AndroidStepHandler androidStepHandler = new AndroidStepHandler(); - androidStepHandler.setTestMode(0, 0, iDevice.getSerialNumber(), DeviceStatus.DEBUGGING, session.getId()); - JSONObject result = new JSONObject(); - AndroidStepHandler finalAndroidStepHandler1 = androidStepHandler; - AndroidDeviceThreadPool.cachedThreadPool.execute(() -> { - try { - AndroidDeviceLocalStatus.startDebug(iDevice.getSerialNumber()); - int port = AndroidDeviceBridgeTool.startUiaServer(iDevice); - finalAndroidStepHandler1.startAndroidDriver(iDevice, port); - result.put("status", "success"); - result.put("detail", "初始化Driver完成!"); - HandlerMap.getAndroidMap().put(session.getId(), finalAndroidStepHandler1); - } catch (Exception e) { - logger.error(e.getMessage()); - result.put("status", "error"); - result.put("detail", "初始化Driver失败!部分功能不可用!请联系管理员"); - finalAndroidStepHandler1.closeAndroidDriver(); - } finally { - result.put("msg", "openDriver"); - BytesTool.sendText(session, result.toJSONString()); - } - }); + synchronized (session) { + AndroidStepHandler androidStepHandler = new AndroidStepHandler(); + androidStepHandler.setTestMode(0, 0, iDevice.getSerialNumber(), DeviceStatus.DEBUGGING, session.getId()); + JSONObject result = new JSONObject(); + AndroidStepHandler finalAndroidStepHandler1 = androidStepHandler; + AndroidDeviceThreadPool.cachedThreadPool.execute(() -> { + try { + AndroidDeviceLocalStatus.startDebug(iDevice.getSerialNumber()); + int port = AndroidDeviceBridgeTool.startUiaServer(iDevice); + finalAndroidStepHandler1.startAndroidDriver(iDevice, port); + result.put("status", "success"); + result.put("detail", "初始化 UIAutomator2 Server 完成!"); + HandlerMap.getAndroidMap().put(session.getId(), finalAndroidStepHandler1); + } catch (Exception e) { + logger.error(e.getMessage()); + result.put("status", "error"); + result.put("detail", "初始化 UIAutomator2 Server 失败!"); + finalAndroidStepHandler1.closeAndroidDriver(); + } finally { + result.put("msg", "openDriver"); + BytesTool.sendText(session, result.toJSONString()); + } + }); + } } private void exit(Session session) { diff --git a/src/main/java/org/cloud/sonic/agent/websockets/IOSWSServer.java b/src/main/java/org/cloud/sonic/agent/websockets/IOSWSServer.java index 25d5a911..5d3f910c 100644 --- a/src/main/java/org/cloud/sonic/agent/websockets/IOSWSServer.java +++ b/src/main/java/org/cloud/sonic/agent/websockets/IOSWSServer.java @@ -121,7 +121,7 @@ public void onOpen(Session session, @PathParam("key") String secretKey, result.put("status", "success"); result.put("width", iosStepHandler.getDriver().getWindowSize().getWidth()); result.put("height", iosStepHandler.getDriver().getWindowSize().getHeight()); - result.put("detail", "初始化Driver完成!"); + result.put("detail", "初始化 WebDriverAgent 完成!"); JSONObject appiumSettings = new JSONObject(); appiumSettings.put("mjpegServerFramerate", 100); appiumSettings.put("mjpegScalingFactor", 100); @@ -131,7 +131,7 @@ public void onOpen(Session session, @PathParam("key") String secretKey, } catch (Exception e) { logger.error(e.getMessage()); result.put("status", "error"); - result.put("detail", "初始化Driver失败!部分功能不可用!请联系管理员"); + result.put("detail", "初始化 WebDriverAgent 失败!"); iosStepHandler.closeIOSDriver(); } finally { result.put("msg", "openDriver"); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 930d9308..6e73ae2a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,9 +9,9 @@ spring: sonic: saa: 2.0.1 sgm: 1.3.3 - sib: 1.2.3 + sib: 1.2.4 sas: 0.0.2 - saus: 5.7.0 + saus: 4.22.1 logging: file: