Skip to content

Commit

Permalink
Feature: reboot devices regularly (#622)
Browse files Browse the repository at this point in the history
<!-- Please provide brief information about the PR, what it contains &
its purpose, new behaviors after the change. And let us know here if you
need any help: https://github.com/microsoft/HydraLab/issues/new -->

## Description

<!-- A few words to explain your changes -->

### Linked GitHub issue ID: #  

## Pull Request Checklist
<!-- Put an x in the boxes that apply. This is simply a reminder of what
we are going to look for before merging your code. -->

- [ ] Tests for the changes have been added (for bug fixes / features)
- [x] Code compiles correctly with all tests are passed.
- [x] I've read the [contributing
guide](https://github.com/microsoft/HydraLab/blob/main/CONTRIBUTING.md#making-changes-to-the-code)
and followed the recommended practices.
- [ ] [Wikis](https://github.com/microsoft/HydraLab/wiki) or
[README](https://github.com/microsoft/HydraLab/blob/main/README.md) have
been reviewed and added / updated if needed (for bug fixes / features)

### Does this introduce a breaking change?
*If this introduces a breaking change for Hydra Lab users, please
describe the impact and migration path.*

- [ ] Yes
- [x] No

## How you tested it
*Please make sure the change is tested, you can test it by adding UTs,
do local test and share the screenshots, etc.*


Please check the type of change your PR introduces:
- [ ] Bugfix
- [x] Feature
- [ ] Technical design
- [ ] Build related changes
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Code style update (formatting, renaming) or Documentation content
changes
- [ ] Other (please describe): 

### Feature UI screenshots or Technical design diagrams
*If this is a relatively large or complex change, kick it off by drawing
the tech design with PlantUML and explaining why you chose the solution
you did and what alternatives you considered, etc...*
  • Loading branch information
zhou9584 authored Nov 28, 2023
1 parent 6f72893 commit 45ec6d9
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -392,4 +392,13 @@ public List<Exception> doActions(TestRunDevice testRunDevice, Logger logger, Map
}
return exceptions;
}

public void rebootDeviceIfNeeded(TestRunDevice testRunDevice, Logger logger) {
if (testRunDevice instanceof TestRunDeviceCombo) {
((TestRunDeviceCombo) testRunDevice).getDevices()
.forEach(testRunDevice1 -> deviceDriverManager.rebootDeviceIfNeeded(testRunDevice1.getDeviceInfo(), logger));
} else {
deviceDriverManager.rebootDeviceIfNeeded(testRunDevice.getDeviceInfo(), logger);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.microsoft.hydralab.agent.config.AppOptions;
import com.microsoft.hydralab.agent.service.DeviceControlService;
import com.microsoft.hydralab.agent.socket.AgentWebSocketClient;
import com.microsoft.hydralab.common.management.device.DeviceType;
import com.microsoft.hydralab.common.util.DateUtil;
import com.microsoft.hydralab.common.util.FileUtil;
import org.slf4j.Logger;
Expand Down Expand Up @@ -50,6 +51,12 @@ public void scheduleCleanBuildSource() {
clearFile(appOptions.getErrorStorageLocation());
}

@Scheduled(cron = "${app.device.auto-reboot.android.cron}")
public void scheduleRestartDevice() {
logger.info("schedule reboot android device");
deviceControlService.rebootDevices(DeviceType.ANDROID);
}

public void clearFile(String folderPath) {
File buildSourceFile = new File(folderPath);
File[] yearFiles = buildSourceFile.listFiles();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.microsoft.hydralab.common.entity.common.DeviceInfo;
import com.microsoft.hydralab.common.entity.common.Message;
import com.microsoft.hydralab.common.management.AgentManagementService;
import com.microsoft.hydralab.common.management.device.DeviceType;
import com.microsoft.hydralab.common.management.device.impl.DeviceDriverManager;
import com.microsoft.hydralab.common.management.listener.DeviceStatusListener;
import com.microsoft.hydralab.common.management.listener.DeviceStatusListenerManager;
Expand All @@ -20,6 +21,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.ArrayList;
Expand Down Expand Up @@ -151,4 +153,16 @@ public void onDeviceConnected(DeviceInfo deviceInfo) {

deviceDriverManager.init();
}

public void rebootDevices(DeviceType deviceType) {
Assert.notNull(deviceType, "deviceType cannot be null");
agentManagementService.getActiveDeviceList(log).stream().filter(deviceInfo -> deviceType.name().equals(deviceInfo.getType()))
.forEach(deviceInfo -> {
try {
deviceDriverManager.rebootDeviceAsync(deviceInfo, log);
} catch (Exception e) {
log.error("Failed to reboot device: {}", deviceInfo.getSerialNum(), e);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ public void onTaskComplete(TestTask testTask) {
public void onOneDeviceComplete(TestTask testTask, TestRunDevice testRunDevice, Logger logger, TestRun result) {
log.info("onOneDeviceComplete: {}", testRunDevice.getDeviceInfo().getSerialNum());
testRunDeviceOrchestrator.finishTask(testRunDevice);
//check if the device is needed to reboot
testRunDeviceOrchestrator.rebootDeviceIfNeeded(testRunDevice, logger);
File deviceTestResultFolder = result.getResultFolder();

File[] files = deviceTestResultFolder.listFiles();
Expand Down
5 changes: 5 additions & 0 deletions agent/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ app:
name: ${AGENT_NAME:default}
# Device Stability Monitor Configuration
device:
auto-reboot:
android:
# '0 0 0 * * ?' means every day at 00:00:00
# '-' means disabled
cron: '-'
monitor:
windows:
enabled: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,8 @@ boolean grantProjectionAndBatteryPermission(@NotNull DeviceInfo deviceInfo,
AppiumServerManager getAppiumServerManager();

void init();

void rebootDeviceAsync(DeviceInfo deviceInfo, Logger logger);

void rebootDeviceIfNeeded(DeviceInfo deviceInfo, Logger logger);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@

import java.io.File;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;


public abstract class AbstractDeviceDriver implements DeviceDriver {
static final Logger classLogger = LoggerFactory.getLogger(AbstractDeviceDriver.class);
protected AgentManagementService agentManagementService;
protected AppiumServerManager appiumServerManager;
protected ConcurrentMap<String, Boolean> rebootDeviceMap = new ConcurrentHashMap<>();

public AbstractDeviceDriver(AgentManagementService agentManagementService,
AppiumServerManager appiumServerManager) {
Expand Down Expand Up @@ -195,4 +198,23 @@ public void execCommandOnAgent(DeviceInfo deviceInfo, String command, Logger log
}
ShellUtils.execLocalCommand(newCommand, logger);
}

public void rebootDeviceAsync(DeviceInfo deviceInfo, Logger logger) {
if (DeviceInfo.TESTING.equals(deviceInfo.getStatus())) {
logger.info("Device {} is testing, will reboot after test finished", deviceInfo.getSerialNum());
rebootDeviceMap.put(deviceInfo.getSerialNum(), true);
} else {
rebootDevice(deviceInfo, logger);
}
}

public void rebootDeviceIfNeeded(DeviceInfo deviceInfo, Logger logger) {
if (rebootDeviceMap.containsKey(deviceInfo.getSerialNum())) {
logger.info("Device {} need to reboot, will reboot it", deviceInfo.getSerialNum());
rebootDevice(deviceInfo, logger);
rebootDeviceMap.remove(deviceInfo.getSerialNum());
}
}

abstract public void rebootDevice(DeviceInfo deviceInfo, Logger logger);
}
Original file line number Diff line number Diff line change
Expand Up @@ -704,9 +704,7 @@ public void testDeviceSetup(@NotNull DeviceInfo deviceInfo, Logger logger) {
changeGlobalSetting(deviceInfo, "window_animation_scale", "0", logger);
changeGlobalSetting(deviceInfo, "transition_animation_scale", "0", logger);
changeGlobalSetting(deviceInfo, "animator_duration_scale", "0", logger);

changeSystemSetting(deviceInfo, "screen_off_timeout", String.valueOf(TimeUnit.MINUTES.toMillis(3)), logger);

enableTouchPositionDisplay(deviceInfo, logger);
}

Expand All @@ -715,7 +713,6 @@ public void testDeviceUnset(DeviceInfo deviceInfo, Logger logger) {
changeGlobalSetting(deviceInfo, "window_animation_scale", "1", logger);
changeGlobalSetting(deviceInfo, "transition_animation_scale", "1", logger);
changeGlobalSetting(deviceInfo, "animator_duration_scale", "1", logger);

changeSystemSetting(deviceInfo, "screen_off_timeout", String.valueOf(TimeUnit.SECONDS.toMillis(45)),
logger);
}
Expand All @@ -735,6 +732,12 @@ public void execCommandOnDevice(DeviceInfo deviceInfo, String command, Logger lo
adbOperateUtil.execOnDevice(deviceInfo, command, new MultiLineNoCancelLoggingReceiver(logger), logger);
}

@Override
public void rebootDevice(DeviceInfo deviceInfo, Logger logger) {
logger.info("Rebooting device {}", deviceInfo.getSerialNum());
adbOperateUtil.execOnDevice(deviceInfo, "reboot", new MultiLineNoCancelLoggingReceiver(logger), logger);
}

@Override
public void removeFileInDevice(DeviceInfo deviceInfo, String pathOnDevice, Logger logger) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

Expand Down Expand Up @@ -216,4 +218,14 @@ public AppiumServerManager getAppiumServerManager() {
ArrayList<DeviceType> keys = new ArrayList<>(deviceDriverMap.keySet());
return deviceDriverMap.get(keys.get(0)).getAppiumServerManager();
}

@Override
public void rebootDeviceAsync(DeviceInfo deviceInfo, Logger logger) {
getDeviceDriver(deviceInfo.getType()).rebootDeviceAsync(deviceInfo, logger);
}

@Override
public void rebootDeviceIfNeeded(DeviceInfo deviceInfo, Logger logger) {
getDeviceDriver(deviceInfo.getType()).rebootDeviceIfNeeded(deviceInfo, logger);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ public void execCommandOnDevice(DeviceInfo deviceInfo, String command, Logger lo
classLogger.info("Nothing Implemented for iOS in " + currentMethodName());
}

@Override
public void rebootDevice(DeviceInfo deviceInfo, Logger logger) {
classLogger.info("Nothing Implemented for iOS in " + currentMethodName());
}

private String currentMethodName() {
return Thread.currentThread().getStackTrace()[2].getMethodName();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ public void execCommandOnDevice(DeviceInfo deviceInfo, String command, Logger lo

}

@Override
public void rebootDevice(DeviceInfo deviceInfo, Logger logger) {
logger.info("Windows device reboot is not supported");
}

@Override
public void screenCapture(DeviceInfo deviceInfo, String outputFile, Logger logger) throws IOException {
File scrFile = appiumServerManager.getWindowsRootDriver(logger).getScreenshotAs(OutputType.FILE);
Expand Down

0 comments on commit 45ec6d9

Please sign in to comment.