Skip to content

Commit

Permalink
Run script on the agent(PC) during the test run (#268)
Browse files Browse the repository at this point in the history
* Run Agent(PC) Script before/after test run
---------

Co-authored-by: Millard <hodin@microsoft.com>
  • Loading branch information
dinghong2233 and Millard authored Feb 14, 2023
1 parent 40c8280 commit ca7a3df
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ public DeviceAction getAction(String commandline) {
deviceAction.getArgs().add(commandline);
return deviceAction;
}
},
AgentShell() {
@Override
public DeviceAction getAction(String commandline) {
DeviceAction deviceAction = new DeviceAction("Windows", "execCommandOnAgent");
deviceAction.getArgs().add(commandline);
return deviceAction;
}
};

public abstract DeviceAction getAction(String commandline);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class ActionExecutor {
* the implementation of supported actions should not be overload
*/
private Set<String> actionTypes = Set.of("setProperty", "setDefaultLauncher", "backToHome", "changeGlobalSetting",
"changeSystemSetting", "execCommandOnDevice", "pushFileToDevice", "pullFileFromDevice");
"changeSystemSetting", "execCommandOnDevice", "execCommandOnAgent", "pushFileToDevice", "pullFileFromDevice");

public List<Exception> doActions(@NotNull DeviceManager deviceManager, @NotNull DeviceInfo deviceInfo, @NotNull Logger logger,
@NotNull Map<String, List<DeviceAction>> actions, @NotNull String when) {
Expand Down
16 changes: 15 additions & 1 deletion agent/src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Available Hydra Lab Variables In Script:
# $HydraLab_TestResultFolderPath: The full path of the test result folder
# $HydraLab_deviceUdid: The UDID of mobile device. (For Android, it will be equal to the serial number)
app:
device-script:
commands:
Expand All @@ -12,8 +15,19 @@ app:
inline: |
test command 2
test command 3
- type: AgentShell
when: setUp
suite-class-matcher: '.*test.*'
inline: |
test command 4
- type: ADBShell
when: tearDown
suite-class-matcher: 'com.microsoft.test'
inline: |
test command 4
test command 5
- type: AgentShell
when: tearDown
suite-class-matcher: 'com.microsoft.test'
inline: |
test command 6
test command 7
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,20 @@ void testAttachCommandAction() {
testTask.setTestSuite("com.microsoft.test");
commandLoader.loadCommandAction(testTask);
Assertions.assertTrue(testTask.getDeviceActions().size() == 2, "Analysis commands failed!");
Assertions.assertTrue(testTask.getDeviceActions().get("setUp").size() == 3, "Analysis commands failed!");
Assertions.assertTrue(testTask.getDeviceActions().get("tearDown").size() == 1, "Analysis commands failed!");
Assertions.assertTrue(testTask.getDeviceActions().get("setUp").size() == 4, "Analysis commands failed!");
Assertions.assertTrue(testTask.getDeviceActions().get("tearDown").size() == 3, "Analysis commands failed!");

AndroidDeviceManager deviceManager = Mockito.mock(AndroidDeviceManager.class);
ActionExecutor actionExecutor = new ActionExecutor();
DeviceInfo deviceInfo = new DeviceInfo();

actionExecutor.doActions(deviceManager, deviceInfo, baseLogger, testTask.getDeviceActions(), DeviceAction.When.SET_UP);
verify(deviceManager, times(3)).execCommandOnDevice(Mockito.any(DeviceInfo.class), Mockito.anyString(), Mockito.any(Logger.class));
verify(deviceManager, times(1)).execCommandOnAgent(Mockito.any(DeviceInfo.class), Mockito.anyString(), Mockito.any(Logger.class));

actionExecutor.doActions(deviceManager, deviceInfo, baseLogger, testTask.getDeviceActions(), DeviceAction.When.TEAR_DOWN);
verify(deviceManager, times(4)).execCommandOnDevice(Mockito.any(DeviceInfo.class), Mockito.anyString(), Mockito.any(Logger.class));
verify(deviceManager, times(3)).execCommandOnAgent(Mockito.any(DeviceInfo.class), Mockito.anyString(), Mockito.any(Logger.class));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import com.android.ddmlib.InstallException;
import com.android.ddmlib.TimeoutException;
import com.microsoft.hydralab.agent.runner.ITestRun;
import com.microsoft.hydralab.agent.runner.TestRunThreadContext;
import com.microsoft.hydralab.common.entity.center.AgentUser;
import com.microsoft.hydralab.common.entity.common.DeviceInfo;
import com.microsoft.hydralab.common.entity.common.TestRun;
Expand All @@ -12,10 +14,7 @@
import com.microsoft.hydralab.common.management.listener.DeviceStatusListenerManager;
import com.microsoft.hydralab.common.management.listener.MobileDeviceState;
import com.microsoft.hydralab.common.screen.ScreenRecorder;
import com.microsoft.hydralab.common.util.IOSUtils;
import com.microsoft.hydralab.common.util.LogUtils;
import com.microsoft.hydralab.common.util.ThreadPoolUtil;
import com.microsoft.hydralab.common.util.ThreadUtils;
import com.microsoft.hydralab.common.util.*;
import com.microsoft.hydralab.common.util.blob.BlobStorageClient;
import io.appium.java_client.appmanagement.ApplicationState;
import io.appium.java_client.ios.IOSDriver;
Expand All @@ -24,6 +23,7 @@
import org.openqa.selenium.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.File;
Expand Down Expand Up @@ -264,7 +264,18 @@ public void updateAllDeviceInfo() {
abstract public void quitMobileAppiumDriver(DeviceInfo deviceInfo, Logger logger);

abstract public void execCommandOnDevice(DeviceInfo deviceInfo, String command, Logger logger);


public void execCommandOnAgent(DeviceInfo deviceInfo, String command, Logger logger) {
ITestRun testRun = TestRunThreadContext.getTestRun();
String newCommand = command;
if (testRun != null) {
// Variable only supported when the test run is ready
Assert.notNull(testRun.getResultFolder(), "The testRun instance in ThreadContext does not have resultFolder property!");
newCommand = ShellUtils.parseHydraLabVariable(command, testRun, deviceInfo);
}
ShellUtils.execLocalCommand(newCommand, logger);
}

protected boolean isAppRunningForeground(DeviceInfo deviceInfo, String packageName, Logger logger) {
IOSDriver iOSDriver = appiumServerManager.getIOSDriver(deviceInfo, logger);
ApplicationState state = iOSDriver.queryAppState(packageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the MIT License.
package com.microsoft.hydralab.common.util;

import com.microsoft.hydralab.agent.runner.ITestRun;
import com.microsoft.hydralab.common.entity.common.DeviceInfo;
import org.slf4j.Logger;

import javax.annotation.Nullable;
Expand All @@ -14,17 +16,18 @@ public class ShellUtils {
private static String[] getFullCommand(String command)
{
String shellProcess = "";
String argName = "";
String args = "";

if (isConnectedToWindowsOS) {
// Add execution policy to ensure powershell can run on most of Windows devices
shellProcess = POWER_SHELL_PATH;
argName = "-Command";
args = "powershell -ExecutionPolicy Unrestricted -NoProfile -Command";
} else {
shellProcess = "sh";
argName = "-c";
args = "-c";
}

return new String[]{shellProcess, argName, command};
return new String[]{shellProcess, args, command};
}

@Nullable
Expand Down Expand Up @@ -101,19 +104,19 @@ public static String execLocalCommandWithResult(String command, Logger classLogg

public static void killProcessByCommandStr(String commandStr, Logger classLogger) {
String shellProcess = "";
String argName = "";
String args = "";
String command = "";
if (isConnectedToWindowsOS) {
String processName = commandStr.split(" ")[0];
shellProcess = POWER_SHELL_PATH;
argName = "-Command";
command = "\"Get-WmiObject Win32_Process -Filter \\\"name like '%" + processName + "%' and CommandLine like '%" + commandStr.replace(" ", "%") + "%'\\\" | Select-Object ProcessId -OutVariable pids; if(-not $pids -eq '' ) {stop-process -id $pids.ProcessId}\"";
args = "-Command";
command = "\"Get-WmiObject Win32_Process -Filter {name like '%" + processName + "%' and CommandLine like '%" + commandStr.replace(" ", "%") + "%'} | Select-Object ProcessId -OutVariable pids; if(-not $pids -eq '' ) {stop-process -id $pids.ProcessId}\"";
} else {
shellProcess = "sh";
argName = "-c";
args = "-c";
command = "kill $(ps aux | grep \"" + commandStr + "\" | grep -v \"grep\" | awk '{print $2}')";
}
String[] fullCommand = {shellProcess, argName, command};
String[] fullCommand = {shellProcess, args, command};
Process process = null;
try {
process = Runtime.getRuntime().exec(fullCommand);
Expand All @@ -129,4 +132,15 @@ public static void killProcessByCommandStr(String commandStr, Logger classLogger
classLogger.error("Fail to run: " + String.join(" ", fullCommand), e);
}
}

public static String parseHydraLabVariable(String command, ITestRun testRun, DeviceInfo deviceInfo) {
// Available Hydra Lab Variables In Script:
// $HydraLab_TestResultFolderPath: The full path of the test result folder
// $HydraLab_deviceUdid: The UDID of mobile device. (For Android, it will be equal to the serial number)
String outPathOnAgent = testRun.getResultFolder().getAbsolutePath() + "/";
String udid = deviceInfo.getSerialNum();
String newCommand = command.replace("$HydraLab_TestResultFolderPath", outPathOnAgent);
newCommand = newCommand.replace("$HydraLab_deviceUdid", udid);
return newCommand;
}
}

0 comments on commit ca7a3df

Please sign in to comment.