diff --git a/center/src/main/java/com/microsoft/hydralab/center/controller/TestTaskController.java b/center/src/main/java/com/microsoft/hydralab/center/controller/TestTaskController.java index 0cd0db5ce..28a277a22 100644 --- a/center/src/main/java/com/microsoft/hydralab/center/controller/TestTaskController.java +++ b/center/src/main/java/com/microsoft/hydralab/center/controller/TestTaskController.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Strings; import com.microsoft.hydralab.center.service.DeviceAgentManagementService; import com.microsoft.hydralab.center.service.SysUserService; import com.microsoft.hydralab.center.service.TestDataService; @@ -80,6 +81,18 @@ public Result runTestTask(@CurrentSecurityContext SysUser requestor, testTaskSpec.teamId = testFileSet.getTeamId(); testTaskSpec.teamName = testFileSet.getTeamName(); testTaskSpec.testTaskId = UUID.randomUUID().toString(); + + if (testTaskSpec.blockDevice && testTaskSpec.unblockDevice) { + throw new IllegalArgumentException("Cannot block and unblock device in the same test task."); + } + if (testTaskSpec.unblockDevice && Strings.isNullOrEmpty(testTaskSpec.unblockDeviceSecretKey)) { + throw new IllegalArgumentException("Unblock secret key is required when unblocking a device."); + } + + if (testTaskSpec.unblockDevice && testTaskSpec.deviceIdentifier.startsWith("G.")) { + throw new IllegalArgumentException("deviceIdentifier should not be a group when unblocking a device."); + } + if (!sysUserService.checkUserAdmin(requestor)) { if (!userTeamManagementService.checkRequestorTeamRelation(requestor, testTaskSpec.teamId)) { return Result.error(HttpStatus.UNAUTHORIZED.value(), "Unauthorized, the TestFileSet doesn't belong to user's Teams"); @@ -89,7 +102,7 @@ public Result runTestTask(@CurrentSecurityContext SysUser requestor, //if the queue is not empty, the task will be added to the queue directly if (testTaskService.isQueueEmpty() || Task.RunnerType.APK_SCANNER.name().equals(testTaskSpec.runningType) - || testTaskService.isDeviceFree(testTaskSpec.deviceIdentifier)) { + || deviceAgentManagementService.isRunOnBlockedDevice(testTaskSpec) || testTaskService.isDeviceFree(testTaskSpec.deviceIdentifier)) { result = deviceAgentManagementService.runTestTaskBySpec(testTaskSpec); if (result.get(Const.Param.TEST_DEVICE_SN) == null) { //if there is no alive device, the task will be added to the queue directly diff --git a/center/src/main/java/com/microsoft/hydralab/center/service/DeviceAgentManagementService.java b/center/src/main/java/com/microsoft/hydralab/center/service/DeviceAgentManagementService.java index 286c70aa7..98ec65ed4 100644 --- a/center/src/main/java/com/microsoft/hydralab/center/service/DeviceAgentManagementService.java +++ b/center/src/main/java/com/microsoft/hydralab/center/service/DeviceAgentManagementService.java @@ -29,6 +29,7 @@ import com.microsoft.hydralab.common.entity.common.TestRun; import com.microsoft.hydralab.common.entity.common.TestTask; import com.microsoft.hydralab.common.entity.common.TestTaskSpec; +import com.microsoft.hydralab.common.entity.common.BlockedDeviceInfo; import com.microsoft.hydralab.common.file.StorageServiceClientProxy; import com.microsoft.hydralab.common.management.device.DeviceType; import com.microsoft.hydralab.common.repository.StatisticDataRepository; @@ -58,6 +59,8 @@ import java.nio.ByteBuffer; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -67,8 +70,10 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -81,7 +86,7 @@ public class DeviceAgentManagementService { * Connected session count */ private final AtomicInteger onlineCount = new AtomicInteger(0); - + private static volatile AtomicBoolean isUnblockingDevices = new AtomicBoolean(false); //save agent session private final ConcurrentHashMap agentSessionMap = new ConcurrentHashMap<>(); //save agent info @@ -94,6 +99,9 @@ public class DeviceAgentManagementService { private final ConcurrentHashMap accessInfoMap = new ConcurrentHashMap<>(); //save agent update info private final ConcurrentHashMap agentUpdateMap = new ConcurrentHashMap<>(); + // save blocked devices + private final ConcurrentHashMap blockedDevicesMap = new ConcurrentHashMap<>(); + @Resource MetricUtil metricUtil; @Resource @@ -695,7 +703,7 @@ public List getAllAppiumAgents() { public JSONObject runTestTaskBySpec(TestTaskSpec testTaskSpec) { JSONObject result; - + unblockFrozenBlockedDevices(); if (Task.RunnerType.APPIUM_CROSS.name().equals(testTaskSpec.runningType)) { result = runAppiumTestTask(testTaskSpec); } else if (Task.RunnerType.T2C_JSON.name().equals(testTaskSpec.runningType)) { @@ -921,12 +929,22 @@ private JSONObject runTestTaskByGroup(TestTaskSpec testTaskSpec) { Assert.isTrue(!isAll, "Device/Agent Offline!"); continue; } + + if (isDeviceBlocked(deviceSerial)) { + Assert.isTrue(!isAll, "Some of the devices in the device group are blocked!"); + continue; + } + isAllOffline = false; if (device.isOnline()) { List devices = testAgentDevicesMap.getOrDefault(device.getAgentId(), new ArrayList<>()); devices.add(device.getSerialNum()); testAgentDevicesMap.put(device.getAgentId(), devices); testTaskSpec.agentIds.add(device.getAgentId()); + if (testTaskSpec.blockDevice) { + testTaskSpec.deviceIdentifier = deviceSerial; + blockDevice(testTaskSpec); + } if (isSingle) { break; } @@ -964,16 +982,27 @@ private JSONObject runTestTaskByDevice(TestTaskSpec testTaskSpec) { Message message = new Message(); message.setBody(testTaskSpec); message.setPath(Const.Path.TEST_TASK_RUN); + Assert.isTrue(device.isAlive(), "Device/Agent Offline!"); - if (device.isTesting()) { + if (device.isTesting() || (!isRunOnBlockedDevice(testTaskSpec) && isDeviceBlocked(testTaskSpec.deviceIdentifier))) { return result; } AgentSessionInfo agentSessionInfoByAgentId = getAgentSessionInfoByAgentId(device.getAgentId()); + Assert.notNull(agentSessionInfoByAgentId, "Device/Agent Offline!"); + if (isAgentUpdating(agentSessionInfoByAgentId.agentUser.getId())) { return result; } updateDeviceStatus(device.getSerialNum(), DeviceInfo.TESTING, testTaskSpec.testTaskId); + + if (testTaskSpec.unblockDevice) { + unBlockDevice(testTaskSpec); + } + + if (testTaskSpec.blockDevice) { + blockDevice(testTaskSpec); + } testTaskSpec.agentIds.add(device.getAgentId()); sendMessageToSession(agentSessionInfoByAgentId.session, message); result.put(Const.Param.TEST_DEVICE_SN, testTaskSpec.deviceIdentifier); @@ -1108,6 +1137,98 @@ public int getAliveDeviceNum() { return (int) deviceListMap.values().stream().filter(DeviceInfo::isAlive).count(); } + public void blockDevice(TestTaskSpec testTaskSpec) { + synchronized (blockedDevicesMap) { + if (blockedDevicesMap.containsKey(testTaskSpec.deviceIdentifier)) { + log.warn("Device {} is already blocked!", testTaskSpec.deviceIdentifier); + return; + } + + BlockedDeviceInfo blockedDeviceInfo = new BlockedDeviceInfo(); + blockedDeviceInfo.setBlockedTime(Instant.now()); + blockedDeviceInfo.setBlockingTaskUUID(testTaskSpec.testTaskId); + blockedDeviceInfo.setBlockedDeviceSerialNumber(testTaskSpec.deviceIdentifier); + blockedDevicesMap.put(testTaskSpec.deviceIdentifier,blockedDeviceInfo); + testTaskSpec.blockedDeviceSerialNumber = testTaskSpec.deviceIdentifier; + testTaskSpec.unblockDeviceSecretKey = testTaskSpec.testTaskId; + } + } + + public boolean isDeviceBlocked(String deviceIdentifier) { + synchronized (blockedDevicesMap) { + return blockedDevicesMap.containsKey(deviceIdentifier); + } + } + + public boolean areAllDevicesBlocked(String deviceIdentifier) { + if (deviceIdentifier.startsWith(Const.DeviceGroup.GROUP_NAME_PREFIX)) { + Set deviceSerials = queryDeviceByGroup(deviceIdentifier); + synchronized (blockedDevicesMap) { + for (String deviceSerial : deviceSerials) { + if (!blockedDevicesMap.containsKey(deviceSerial)) { + return false; + } + } + } + return true; + } else { + return false; + } + } + + public void unBlockDevice(TestTaskSpec testTaskSpec) { + synchronized (blockedDevicesMap) { + if (blockedDevicesMap.containsKey(testTaskSpec.deviceIdentifier)) { + BlockedDeviceInfo blockedDeviceInfo = blockedDevicesMap.get(testTaskSpec.deviceIdentifier); + if (blockedDeviceInfo.getBlockingTaskUUID().equals(testTaskSpec.unblockDeviceSecretKey)) { + blockedDevicesMap.remove(testTaskSpec.deviceIdentifier); + testTaskSpec.unblockedDeviceSerialNumber = testTaskSpec.deviceIdentifier; + } else { + throw new IllegalArgumentException("Invalid unblock device secret key!"); + } + } else { + log.warn("Device {} is already unblocked.", testTaskSpec.deviceIdentifier); + testTaskSpec.unblockedDeviceSerialNumber = testTaskSpec.deviceIdentifier; + } + } + } + + public void unblockFrozenBlockedDevices() { + if (isUnblockingDevices.get()){ + return; + } + isUnblockingDevices.set(true); + synchronized (blockedDevicesMap) { + Instant currentTime = Instant.now(); + Iterator> iterator = blockedDevicesMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + Instant blockedTime = entry.getValue().getBlockedTime(); + Duration durationBlocked = Duration.between(blockedTime, currentTime); + if (durationBlocked.compareTo(Const.DeviceGroup.BLOCKED_DEVICE_TIMEOUT) > 0) { + log.info("Unblocking device {} since it has been blocked for more than {} hours.", entry.getKey(), durationBlocked); + iterator.remove(); + } + } + } + isUnblockingDevices.set(false); + } + + public boolean isRunOnBlockedDevice(TestTaskSpec testTaskSpec) { + if (testTaskSpec.unblockDeviceSecretKey == null || testTaskSpec.unblockDeviceSecretKey.isEmpty()) { + return false; + } + + synchronized (blockedDevicesMap) { + BlockedDeviceInfo blockedDeviceInfo = blockedDevicesMap.get(testTaskSpec.deviceIdentifier); + + if (blockedDeviceInfo == null) { + return false; + } + return blockedDeviceInfo.getBlockingTaskUUID().equals(testTaskSpec.unblockDeviceSecretKey); + } + } + @Scheduled(cron = "0 * * * * *") public void recordStatisticData() { int currentAgentNum = getAliveAgentNum(); diff --git a/center/src/main/java/com/microsoft/hydralab/center/service/TestTaskService.java b/center/src/main/java/com/microsoft/hydralab/center/service/TestTaskService.java index 0655bafe0..08f139658 100644 --- a/center/src/main/java/com/microsoft/hydralab/center/service/TestTaskService.java +++ b/center/src/main/java/com/microsoft/hydralab/center/service/TestTaskService.java @@ -66,8 +66,16 @@ public Boolean isDeviceFree(String deviceIdentifier) { relatedIdentifiers.addAll(deviceAgentManagementService.queryGroupByDevice(deviceIdentifier)); } } else if (deviceIdentifier.startsWith(Const.DeviceGroup.GROUP_NAME_PREFIX)) { + if (deviceAgentManagementService.areAllDevicesBlocked(deviceIdentifier)) { + logger.warn("All Devices in the DeviceGroup " + deviceIdentifier + " are blocked currently."); + return false; + } relatedIdentifiers.addAll(deviceAgentManagementService.queryDeviceByGroup(deviceIdentifier)); } else { + if (deviceAgentManagementService.isDeviceBlocked(deviceIdentifier)) { + logger.warn("Device " + deviceIdentifier + " is blocked currently."); + return false; + } relatedIdentifiers.addAll(deviceAgentManagementService.queryGroupByDevice(deviceIdentifier)); } synchronized (taskQueue) { @@ -92,6 +100,7 @@ public void runTask() { return; } isRunning.set(true); + synchronized (taskQueue) { Iterator queueIterator = taskQueue.iterator(); while (queueIterator.hasNext()) { diff --git a/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlockedDeviceInfo.java b/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlockedDeviceInfo.java new file mode 100644 index 000000000..ff7efe3e2 --- /dev/null +++ b/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlockedDeviceInfo.java @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +package com.microsoft.hydralab.common.entity.common; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.time.Instant; + +@Getter +@Setter +@ToString +public class BlockedDeviceInfo { + public Instant blockedTime; + public String blockingTaskUUID; + public String blockedDeviceSerialNumber; +} diff --git a/common/src/main/java/com/microsoft/hydralab/common/entity/common/Task.java b/common/src/main/java/com/microsoft/hydralab/common/entity/common/Task.java index 42ac0a0b6..753227f48 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/entity/common/Task.java +++ b/common/src/main/java/com/microsoft/hydralab/common/entity/common/Task.java @@ -86,6 +86,13 @@ public class Task implements Serializable { private boolean disableRecording = false; @Column(columnDefinition = "boolean default false") private boolean isSucceed = false; + public String blockedDeviceSerialNumber; + public String unblockedDeviceSerialNumber; + public String unblockDeviceSecretKey; + @Transient + public boolean blockDevice = false; + @Transient + public boolean unblockDevice = false; @Transient private List deviceTestResults; @@ -164,6 +171,16 @@ public TestTaskSpec convertToTaskSpec() { testTaskSpec.disableRecording = isDisableRecording(); testTaskSpec.retryTime = getRetryTime(); + if (isBlockDevice()) { + testTaskSpec.blockDevice = true; + testTaskSpec.blockedDeviceSerialNumber = getBlockedDeviceSerialNumber(); + testTaskSpec.unblockDeviceSecretKey = getUnblockDeviceSecretKey(); + } + if (isUnblockDevice()) { + testTaskSpec.unblockDevice = true; + testTaskSpec.unblockedDeviceSerialNumber = getUnblockedDeviceSerialNumber(); + testTaskSpec.unblockDeviceSecretKey = getUnblockDeviceSecretKey(); + } return testTaskSpec; } @@ -198,6 +215,18 @@ public Task(TestTaskSpec testTaskSpec) { setTeamName(testTaskSpec.teamName); setNotifyUrl(testTaskSpec.notifyUrl); setDisableRecording(testTaskSpec.disableRecording); + + if (testTaskSpec.blockDevice) { + setBlockDevice(true); + setBlockedDeviceSerialNumber(testTaskSpec.blockedDeviceSerialNumber); + setUnblockDeviceSecretKey(testTaskSpec.unblockDeviceSecretKey); + } + + if (testTaskSpec.unblockDevice) { + setUnblockDevice(true); + setUnblockedDeviceSerialNumber(testTaskSpec.unblockedDeviceSerialNumber); + setUnblockDeviceSecretKey(testTaskSpec.unblockDeviceSecretKey); + } } public Task() { diff --git a/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestTaskSpec.java b/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestTaskSpec.java index 63d14d3a1..d501dda0b 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestTaskSpec.java +++ b/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestTaskSpec.java @@ -57,6 +57,11 @@ public class TestTaskSpec { public boolean enableNetworkMonitor; public String networkMonitorRule; public boolean enableTestOrchestrator = false; + public boolean blockDevice = false; + public boolean unblockDevice = false; + public String blockedDeviceSerialNumber; + public String unblockedDeviceSerialNumber; + public String unblockDeviceSecretKey; public void updateWithDefaultValues() { determineScopeOfTestCase(); diff --git a/common/src/main/java/com/microsoft/hydralab/common/util/Const.java b/common/src/main/java/com/microsoft/hydralab/common/util/Const.java index 948a2f42d..4abd74273 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/util/Const.java +++ b/common/src/main/java/com/microsoft/hydralab/common/util/Const.java @@ -3,6 +3,7 @@ package com.microsoft.hydralab.common.util; +import java.time.Duration; import java.util.List; public interface Const { @@ -32,6 +33,7 @@ interface DeviceGroup { String SINGLE_TYPE = "SINGLE"; String REST_TYPE = "REST"; String ALL_TYPE = "ALL"; + Duration BLOCKED_DEVICE_TIMEOUT = Duration.ofHours(4); } interface AgentConfig { diff --git a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/ClientUtilsPlugin.groovy b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/ClientUtilsPlugin.groovy index 4ec5f84ab..1bf971f4f 100644 --- a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/ClientUtilsPlugin.groovy +++ b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/ClientUtilsPlugin.groovy @@ -11,6 +11,7 @@ import com.microsoft.hydralab.utils.YamlParser import org.apache.commons.lang3.StringUtils import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.internal.impldep.com.sun.xml.bind.v2.runtime.reflect.opt.Const class ClientUtilsPlugin implements Plugin { @@ -173,6 +174,18 @@ class ClientUtilsPlugin implements Plugin { // add quotes back as quotes in gradle plugins will be replaced by blanks testConfig.analysisConfigsStr = project.analysisConfigsStr.replace("\\", "\"") } + if (project.hasProperty('blockDevice')) { + // block a device from a group of devices + testConfig.blockDevice = project.blockDevice + } + if (project.hasProperty('unblockDevice')) { + // unblock a device + testConfig.unblockDevice = project.unblockDevice + } + if (project.hasProperty('unblockDeviceSecretKey')) { + // secret key to unblock a device + testConfig.unblockDeviceSecretKey = project.unblockDeviceSecretKey + } requiredParamCheck(apiConfig, testConfig) @@ -211,6 +224,15 @@ class ClientUtilsPlugin implements Plugin { if (StringUtils.isBlank(testConfig.testSuiteName)) { throw new IllegalArgumentException('Running type ' + testConfig.runningType + ' required param testSuiteName not provided!') } + if (testConfig.unblockDevice && StringUtils.isBlank(testConfig.unblockDeviceSecretKey)) { + throw new IllegalArgumentException('Running type ' + testConfig.runningType + ' required param unblockDeviceSecretKey not provided!') + } + if (testConfig.blockDevice && testConfig.unblockDevice) { + throw new IllegalArgumentException('Running type ' + testConfig.runningType + ' param block and unblock device should not be true in the same test task!') + } + if(testConfig.unblockDevice && testConfig.deviceConfig.deviceIdentifier.startsWith("G.")) { + throw new IllegalArgumentException('Running type ' + testConfig.runningType + ' param deviceIdentifier should not be a Group when unblockDevice is set to true!') + } break case "APPIUM": if (StringUtils.isBlank(testConfig.testAppPath)) { diff --git a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/config/TestConfig.java b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/config/TestConfig.java index 02ce07e07..3c7d716ca 100644 --- a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/config/TestConfig.java +++ b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/config/TestConfig.java @@ -60,6 +60,9 @@ public class TestConfig { public boolean enableTestOrchestrator = false; public List analysisConfigs = new ArrayList<>(); public String analysisConfigsStr = ""; + public Boolean blockDevice = false; + public Boolean unblockDevice = false; + public String unblockDeviceSecretKey = ""; public void constructField(HashMap map) { Object queueTimeOutSeconds = map.get("queueTimeOutSeconds"); diff --git a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/entity/TestTask.java b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/entity/TestTask.java index 81b36040c..ce5494b07 100644 --- a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/entity/TestTask.java +++ b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/entity/TestTask.java @@ -19,6 +19,9 @@ public class TestTask { public String testErrorMsg; public String message; public int retryTime; + public String blockedDeviceSerialNumber; + public String unblockedDeviceSerialNumber; + public String unblockDeviceSecretKey; @Override public String toString() { diff --git a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabAPIClient.java b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabAPIClient.java index 22b32cb87..db947eb87 100644 --- a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabAPIClient.java +++ b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabAPIClient.java @@ -240,6 +240,9 @@ public JsonObject triggerTestRun(TestConfig testConfig, HydraLabAPIConfig apiCon jsonElement.addProperty("networkMonitorRule", testConfig.networkMonitorRule); jsonElement.addProperty("enableTestOrchestrator", testConfig.enableTestOrchestrator); jsonElement.addProperty("notifyUrl", testConfig.notifyUrl); + jsonElement.addProperty("blockDevice", testConfig.blockDevice); + jsonElement.addProperty("unblockDevice", testConfig.unblockDevice); + jsonElement.addProperty("unblockDeviceSecretKey", testConfig.unblockDeviceSecretKey); try { if (testConfig.neededPermissions.size() > 0) { diff --git a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabClientUtils.java b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabClientUtils.java index abc17c57b..044c5cfae 100644 --- a/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabClientUtils.java +++ b/gradle_plugin/src/main/groovy/com/microsoft/hydralab/utils/HydraLabClientUtils.java @@ -224,6 +224,15 @@ private static void runTestInner(String reportFolderPath, HydraLabAPIConfig apiC assertNotNull(runningTest, "runningTest"); assertNotNull(runningTest.deviceTestResults, "runningTest.deviceTestResults"); + if (testConfig.blockDevice) { + assertNotNull(runningTest.blockedDeviceSerialNumber, "blockedDeviceSerialNumber"); + printlnf("##vso[task.setvariable variable=BlockedDeviceSerialNumber;isOutput=true]%s", runningTest.blockedDeviceSerialNumber); + printlnf("##vso[task.setvariable variable=UnblockDeviceSecretKey;isOutput=true]%s", runningTest.unblockDeviceSecretKey); + } + + if (testConfig.unblockDevice && testConfig.deviceConfig.deviceIdentifier.equals(runningTest.unblockedDeviceSerialNumber)) { + printlnf("##[section] Device % s, unblocked.", runningTest.unblockedDeviceSerialNumber); + } String testReportUrl = apiConfig.getTestReportUrl(runningTest.id); diff --git a/gradle_plugin/src/test/java/com/microsoft/hydralab/ClientUtilsPluginTest.java b/gradle_plugin/src/test/java/com/microsoft/hydralab/ClientUtilsPluginTest.java index 4926bd2f1..c1a2d60e0 100644 --- a/gradle_plugin/src/test/java/com/microsoft/hydralab/ClientUtilsPluginTest.java +++ b/gradle_plugin/src/test/java/com/microsoft/hydralab/ClientUtilsPluginTest.java @@ -82,6 +82,9 @@ public void checkInstrumentationTestRequiredParam() { testConfig.testSuiteName = ""; testConfig.testPkgName = ""; testConfig.testScope = ""; + testConfig.unblockDevice = false; + testConfig.blockDevice = false; + testConfig.unblockDeviceSecretKey = ""; apiConfig.host = "www.test.host"; apiConfig.authToken = "thisisanauthtokenonlyfortest"; deviceConfig.deviceIdentifier = "TESTDEVICESN001"; @@ -107,6 +110,21 @@ public void checkInstrumentationTestRequiredParam() { testConfig.testScope = ClientUtilsPlugin.TestScope.CLASS; clientUtilsPlugin.requiredParamCheck(apiConfig, testConfig); + + testConfig.unblockDevice = true; + typeSpecificParamCheck(apiConfig, testConfig, "unblockDeviceSecretKey"); + + testConfig.unblockDeviceSecretKey = "UNBLOCKDEVICESECRET001"; + testConfig.blockDevice = true; + typeSpecificParamCheck(apiConfig, testConfig, "blockUnblockDevice"); + testConfig.blockDevice = false; + + deviceConfig.deviceIdentifier = "G.GROUP001"; + typeSpecificParamCheck(apiConfig, testConfig, "unblockDeviceGroup"); + + deviceConfig.deviceIdentifier = "TESTDEVICESN001"; + + clientUtilsPlugin.requiredParamCheck(apiConfig, testConfig); } @Test @@ -171,6 +189,8 @@ public void runTestOnDeviceWithApp() { testConfig.appPath = "src/test/resources/app.txt"; testConfig.testAppPath = "src/test/resources/test_app.txt"; testConfig.attachmentInfos = new ArrayList<>(); + testConfig.blockDevice = true; + testConfig.unblockDevice = false; String returnId = "id123456"; when(client.uploadApp(Mockito.any(HydraLabAPIConfig.class), Mockito.any(TestConfig.class), Mockito.anyString(), Mockito.anyString(), @@ -207,6 +227,8 @@ public void runTestOnDeviceWithApp() { returnTestTask.totalTestCount = 5; returnTestTask.totalFailCount = 1; returnTestTask.reportImagePath = "./image_path/image"; + returnTestTask.blockedDeviceSerialNumber = "TESTDEVICESN001"; + returnTestTask.unblockDeviceSecretKey = "UNBLOCKDEVICESECRET001"; when(client.getTestStatus(Mockito.any(HydraLabAPIConfig.class), Mockito.anyString())) .thenReturn(returnTestTask); @@ -251,6 +273,13 @@ private void typeSpecificParamCheck(HydraLabAPIConfig apiConfig, TestConfig test IllegalArgumentException thrown = Assertions.assertThrows(IllegalArgumentException.class, () -> { clientUtilsPlugin.requiredParamCheck(apiConfig, testConfig); }, "IllegalArgumentException was expected"); - Assertions.assertEquals("Running type " + testConfig.runningType + " required param " + requiredParamName + " not provided!", thrown.getMessage()); + if (requiredParamName.equals("blockUnblockDevice")) { + Assertions.assertEquals("Running type " + testConfig.runningType + " param block and unblock device should not be true in the same test task!", thrown.getMessage()); + } else if(requiredParamName.equals("unblockDeviceGroup")) { + Assertions.assertEquals("Running type " + testConfig.runningType + " param deviceIdentifier should not be a Group when unblockDevice is set to true!", thrown.getMessage()); + } + else { + Assertions.assertEquals("Running type " + testConfig.runningType + " required param " + requiredParamName + " not provided!", thrown.getMessage()); + } } } \ No newline at end of file