Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run script on the agent(PC) during the test run #268

Merged
merged 8 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -254,7 +254,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();
dinghong2233 marked this conversation as resolved.
Show resolved Hide resolved
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";
AC-Phoenix marked this conversation as resolved.
Show resolved Hide resolved
} 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;
}
}