diff --git a/README.md b/README.md index a0c537ceb..163668543 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,15 @@ docker pull ghcr.io/microsoft/hydra-lab-uber:latest **Step 2. run on your machine with BLOB_CONNECTION_STR** -You may write the content "BLOB_CONNECTION_STR=${YOUR_BLOB_CONNECTION_STR}" in an env file, and pass the path of the file to docker container: -``` -docker run [-p 9886:9886] [--name=hydra-lab] --env-file ${YOUR_ENV_FILE_PATH} ghcr.io/microsoft/hydra-lab-uber:latest +You may write the content `BLOB_CONNECTION_STR=${YOUR_BLOB_CONNECTION_STR}` in an env file (e.g. env.txt), and pass the path of the file to docker container: + +```bash +docker run --env-file env.txt -p 9886:9886 --name=hydra-lab ghcr.io/microsoft/hydra-lab-uber:latest ``` Or simply run with the env parameter -e: -``` -docker run [-p 9886:9886] [--name=hydra-lab] -e BLOB_CONNECTION_STR=${YOUR_BLOB_CONNECTION_STR} ghcr.io/microsoft/hydra-lab-uber:latest + +```bash +docker run -e BLOB_CONNECTION_STR=${YOUR_BLOB_CONNECTION_STR} -p 9886:9886 --name=hydra-lab ghcr.io/microsoft/hydra-lab-uber:latest ``` **Step 3. visit front-end page and view your connected devices** diff --git a/README.zh-CN.md b/README.zh-CN.md index 0d7ad776c..515d1459a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -30,7 +30,7 @@ Hydra Lab 的特性包括: - 支持在不同平台上进行 Appium(Java) 测试:Windows/iOS/Android/浏览器/跨平台。 - 无用例的自动化测试:Monkey test,智能探索测试 -更多细节,请参见 [介绍:什么是 Hydra Lab?](https://github.com/microsoft/HydraLab/wiki) +更多细节,请参见 [什么是 Hydra Lab?](https://github.com/microsoft/HydraLab/wiki) ## 入门 @@ -121,12 +121,12 @@ java -jar agent/build/libs/agent.jar > Note: If you are a Microsoft FTE and want to onboard to the internal Hydra Lab testing service, please visit [our SharePoint site](https://microsoftapc.sharepoint.com/teams/MMXDocument/SitePages/Hydra-Lab-test-automation-service-onboarding-guideline.aspx) to learn more about the internal service instance. -### For Contributor: +### 参与贡献Hydra Lab: - [Contribute to the Hydra Lab GitHub Project](https://github.com/microsoft/HydraLab/wiki/Contribute-to-the-Hydra-Lab-GitHub-Project) -## Who are using Hydra Lab? +## 谁在使用Hydra Lab? It's already powering the UI test automation of the following Microsoft products: - Microsoft Phone Link (Windows UWP app) and Link to Windows (Android app) diff --git a/agent/agent_installer/Windows/AgentService.exe b/agent/agent_installer/Windows/AgentService.exe new file mode 100644 index 000000000..ff0969302 Binary files /dev/null and b/agent/agent_installer/Windows/AgentService.exe differ diff --git a/agent/agent_installer/Windows/AgentService.xml b/agent/agent_installer/Windows/AgentService.xml new file mode 100644 index 000000000..e0353223b --- /dev/null +++ b/agent/agent_installer/Windows/AgentService.xml @@ -0,0 +1,13 @@ + +Hydra Lab Agent Service +Hydra Lab Agent Service +Hydra Lab Test Agent Service serves as the test runner and test device manager of the connected Hydra Lab center. + +java +-Xms1024m -Xmx2048m -jar agent.jar +Automatic + {LOG_FILE_LOCATION} + +yyyyMMdd + + \ No newline at end of file diff --git a/agent/agent_installer/Windows/restartAgent.bat b/agent/agent_installer/Windows/restartAgent.bat index 3f16799ea..f2face9b2 100644 --- a/agent/agent_installer/Windows/restartAgent.bat +++ b/agent/agent_installer/Windows/restartAgent.bat @@ -13,8 +13,11 @@ exit /B if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" ) echo newfile = %1 -set newfile=%1 +set newfile = %1 +::stop hydra lab agent service net stop "Hydra Lab Agent Service" +::kill hydra lab agent java process +::Powershell -Command "& {Get-WmiObject Win32_Process -Filter \"name like '%%java%%' and CommandLine like '%%agent%%'\" | Select-Object ProcessId -OutVariable pids;if(-not $pids -eq '' ) {stop-process -id $pids.ProcessId}}" if "%newfile%"=="" ( echo "No need to update" ) else ( if not exist "%newfile%" ( echo "%newfile% not exist" ) else ( echo "Updating" @@ -22,4 +25,7 @@ if "%newfile%"=="" ( echo "No need to update" ) else ( ren "%newfile%" agent.jar ) ) +::start hydra lab agent in command mode +::java -Xms1024m -Xmx4096m -jar .\agent.jar +::start hydra lab agent in windows service mode net start "Hydra Lab Agent Service" \ No newline at end of file diff --git a/agent/src/main/java/com/microsoft/hydralab/agent/runner/ActionExecutor.java b/agent/src/main/java/com/microsoft/hydralab/agent/runner/ActionExecutor.java index f329ce711..f6a4fec8d 100644 --- a/agent/src/main/java/com/microsoft/hydralab/agent/runner/ActionExecutor.java +++ b/agent/src/main/java/com/microsoft/hydralab/agent/runner/ActionExecutor.java @@ -10,6 +10,7 @@ import com.microsoft.hydralab.common.util.ThreadUtils; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; +import org.springframework.http.HttpStatus; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -94,7 +95,7 @@ private Object[] convertArgs(@NotNull DeviceInfo deviceInfo, @NotNull Logger log try { methodArgs[i + 1] = JSONObject.parseObject(actionArgs.get(i), DeviceAction.class); } catch (Exception e1) { - throw new HydraLabRuntimeException(500, "Convert arg failed!", e1); + throw new HydraLabRuntimeException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Convert arg failed!", e1); } } } diff --git a/agent/src/main/java/com/microsoft/hydralab/agent/runner/TestRunner.java b/agent/src/main/java/com/microsoft/hydralab/agent/runner/TestRunner.java index c965ffa68..10246bce5 100644 --- a/agent/src/main/java/com/microsoft/hydralab/agent/runner/TestRunner.java +++ b/agent/src/main/java/com/microsoft/hydralab/agent/runner/TestRunner.java @@ -57,6 +57,7 @@ public void runTestOnDevice(TestTask testTask, DeviceInfo deviceInfo, Logger log private void runByFutureTask(DeviceInfo deviceInfo, TestTask testTask, TestRun testRun) throws Exception { FutureTask futureTask = new FutureTask<>(() -> { + initTestRunThreadContext(testRun); run(deviceInfo, testTask, testRun); return null; }); @@ -74,6 +75,14 @@ private void runByFutureTask(DeviceInfo deviceInfo, TestTask testTask, TestRun t } } + /** + * TODO Call {@link TestRunThreadContext#init(ITestRun)} + * This method must be called in the test run execution thread. + */ + private void initTestRunThreadContext(TestRun testRun) { + + } + private static void saveErrorSummary(TestRun testRun, Exception e) { String errorStr = e.getClass().getName() + ": " + e.getMessage(); if (errorStr.length() > 255) { @@ -201,7 +210,7 @@ protected void reInstallApp(DeviceInfo deviceInfo, TestTask testTask, Logger rep } protected void reInstallTestApp(DeviceInfo deviceInfo, TestTask testTask, Logger reportLogger) throws Exception { - if(!shouldInstallTestPackageAsApp()){ + if (!shouldInstallTestPackageAsApp()) { return; } if (testTask.getTestAppFile() == null) { diff --git a/azure-pipelines-ci.yml b/azure-pipelines-ci.yml index 48a02831e..7c466847c 100644 --- a/azure-pipelines-ci.yml +++ b/azure-pipelines-ci.yml @@ -112,6 +112,28 @@ stages: Contents: '*.jar' TargetFolder: '$(Build.ArtifactStagingDirectory)/center_deploy' condition: and(succeeded(), eq(variables.fullBuild, 'true')) + - task: Gradle@2 + displayName: Package Mac installer + inputs: + gradleWrapperFile: 'gradlew' + tasks: 'packageMacInstaller' + publishJUnitResults: false + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + sonarQubeRunAnalysis: false + spotBugsAnalysis: false + condition: and(succeeded(), eq(variables.fullBuild, 'true')) + - task: Gradle@2 + displayName: Package Windows installer + inputs: + gradleWrapperFile: 'gradlew' + tasks: 'packageWindowsInstaller' + publishJUnitResults: false + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + sonarQubeRunAnalysis: false + spotBugsAnalysis: false + condition: and(succeeded(), eq(variables.fullBuild, 'true')) - task: CopyFiles@2 displayName: Copy agent jar inputs: @@ -119,6 +141,13 @@ stages: Contents: '*.jar' TargetFolder: '$(Build.ArtifactStagingDirectory)/agent_deploy' condition: and(succeeded(), eq(variables.fullBuild, 'true')) + - task: CopyFiles@2 + displayName: Copy agent installer + inputs: + SourceFolder: 'build/installer/' + Contents: '*.zip' + TargetFolder: '$(Build.ArtifactStagingDirectory)/agent_deploy' + condition: and(succeeded(), eq(variables.fullBuild, 'true')) - task: CopyFiles@2 displayName: Copy deploy uber files inputs: diff --git a/build.gradle b/build.gradle index d806199f1..ce9fe21b2 100644 --- a/build.gradle +++ b/build.gradle @@ -77,3 +77,15 @@ task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') { xml.enabled true } } + +task packageMacInstaller(type: Zip) { + from 'agent/agent_installer/MacOS/iOS' + archiveName 'Hydra_Agent_Installer_Mac.zip' + destinationDir file('build/installer') +} + +task packageWindowsInstaller(type: Zip) { + from 'agent/agent_installer/Windows' + archiveName 'Hydra_Agent_Installer_Windows.zip' + destinationDir file('build/installer') +} \ No newline at end of file diff --git a/center/build.gradle b/center/build.gradle index 078ac7966..eb8530180 100644 --- a/center/build.gradle +++ b/center/build.gradle @@ -8,6 +8,10 @@ version = hydraLabVersion sourceCompatibility = 11 targetCompatibility = 11 +repositories { + mavenCentral() +} + bootJar { // Specify the out jar file name so that the dockerfile could copy it // without concerning the name change caused by version change. @@ -60,6 +64,18 @@ dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.20' } -repositories { - mavenCentral() -} \ No newline at end of file +import org.apache.tools.ant.taskdefs.condition.Os +String npmCommand = 'npm' +if (Os.isFamily(Os.FAMILY_WINDOWS)) { + npmCommand = 'npm.cmd' +} +String reactDir = "${projectDir.parentFile.absolutePath}${File.separator}react" +task installWebFront(type: Exec, group: 'build') { + workingDir reactDir + commandLine npmCommand, 'ci' +} + +task buildWebFront(type: Exec, group: 'build', dependsOn: installWebFront) { + workingDir reactDir + commandLine npmCommand, 'run', 'pub' +} diff --git a/center/deploy_startup/alert_notification.html b/center/deploy_startup/alert_notification.html index 474339b4b..225127bcd 100644 --- a/center/deploy_startup/alert_notification.html +++ b/center/deploy_startup/alert_notification.html @@ -183,7 +183,7 @@ 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 4c6c6c5a4..b8615bdc9 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 @@ -72,9 +72,7 @@ public Result runTestTask(@CurrentSecurityContext SysUser requestor, if (!userTeamManagementService.checkRequestorTeamRelation(requestor, testTaskSpec.teamId)) { return Result.error(HttpStatus.UNAUTHORIZED.value(), "Unauthorized, the TestFileSet doesn't belong to user's Teams"); } - if (!testTaskService.checkTestTaskTeamConsistency(testTaskSpec)) { - return Result.error(HttpStatus.UNAUTHORIZED.value(), "Unauthorized, the TestTask is requiring deviceIdentifier that doesn't belong to user's Teams"); - } + testTaskService.checkTestTaskTeamConsistency(testTaskSpec); } //if the queue is not empty, the task will be added to the queue directly if (testTaskService.isQueueEmpty() || testTaskService.isDeviceFree(testTaskSpec.deviceIdentifier)) { 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 fd224ed25..738ae6bf5 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 @@ -13,10 +13,7 @@ import com.microsoft.hydralab.common.entity.common.*; import com.microsoft.hydralab.common.repository.BlobFileInfoRepository; import com.microsoft.hydralab.common.repository.StatisticDataRepository; -import com.microsoft.hydralab.common.util.AttachmentService; -import com.microsoft.hydralab.common.util.Const; -import com.microsoft.hydralab.common.util.GlobalConstant; -import com.microsoft.hydralab.common.util.SerializeUtil; +import com.microsoft.hydralab.common.util.*; import com.microsoft.hydralab.common.util.blob.BlobStorageClient; import com.microsoft.hydralab.t2c.runner.DriverInfo; import com.microsoft.hydralab.t2c.runner.T2CJsonParser; @@ -24,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -305,18 +303,18 @@ public void cancelTestTaskById(String taskId, String reason) { public void checkAccessInfo(String name, String key) { if (key == null) { - throw new RuntimeException("access key is required!"); + throw new HydraLabRuntimeException(HttpStatus.UNAUTHORIZED.value(), "Access key is required!"); } AccessInfo accessInfo = accessInfoMap.get(name); - if (accessInfo != null) { - throw new RuntimeException("please generate access key first!"); + if (accessInfo == null) { + throw new HydraLabRuntimeException(HttpStatus.UNAUTHORIZED.value(), "Please generate access key first!"); } if (!key.equals(accessInfo.getKey())) { - throw new RuntimeException("error access key!"); + throw new HydraLabRuntimeException(HttpStatus.UNAUTHORIZED.value(), "Error access key!"); } int hour = (int) ((new Date().getTime() - accessInfo.getIngestTime().getTime()) / 1000 / 60 / 60); if (hour > accessLimit) { - throw new RuntimeException("access key has expired!"); + throw new HydraLabRuntimeException(HttpStatus.UNAUTHORIZED.value(), "Access key has expired!"); } } 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 fd0e4da63..8f8b100ae 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 @@ -10,9 +10,11 @@ import com.microsoft.hydralab.common.entity.common.DeviceInfo; import com.microsoft.hydralab.common.entity.common.TestTask; import com.microsoft.hydralab.common.util.Const; +import com.microsoft.hydralab.common.util.HydraLabRuntimeException; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -138,46 +140,46 @@ public TestTaskQueuedInfo getTestQueuedInfo(String testTaskId) { return taskQueuedInfo; } - public boolean checkTestTaskTeamConsistency(TestTaskSpec testTaskSpec) { + public void checkTestTaskTeamConsistency(TestTaskSpec testTaskSpec) throws HydraLabRuntimeException { if (TestTask.TestRunningType.APPIUM_CROSS.equals(testTaskSpec.runningType) || TestTask.TestRunningType.T2C_JSON_TEST.equals(testTaskSpec.runningType)) { AgentUser agent = agentManageService.getAgent(testTaskSpec.deviceIdentifier); if (agent == null) { - return false; + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "Didn't find AgentUser with given deviceIdentifier!"); + } + if (!testTaskSpec.teamId.equals(agent.getTeamId())) { + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "AgentUser doesn't belong to the given team in spec!"); } - return testTaskSpec.teamId.equals(agent.getTeamId()); } else { String deviceIdentifier = testTaskSpec.deviceIdentifier; if (deviceIdentifier.startsWith(Const.DeviceGroup.GROUP_NAME_PREFIX)) { DeviceGroup deviceGroup = deviceGroupService.getGroupByName(deviceIdentifier); if (deviceGroup == null) { - return false; + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "Didn't find DeviceGroup with given deviceIdentifier!"); } if (testTaskSpec.teamId.equals(deviceGroup.getTeamId())) { - return true; + return; } if (!deviceGroup.getIsPrivate()) { - return true; + return; } deviceAgentManagementService.checkAccessInfo(deviceIdentifier, testTaskSpec.accessKey); - return true; } else { DeviceInfo device = deviceAgentManagementService.getDevice(deviceIdentifier); if (device == null) { - return false; + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "Didn't find device with given deviceIdentifier!"); } AgentUser agent = agentManageService.getAgent(device.getAgentId()); if (agent == null) { - return false; + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "Didn't find AgentUser with given agent id!"); } if (testTaskSpec.teamId.equals(agent.getTeamId())) { - return true; + return; } if (!device.getIsPrivate()) { - return true; + return; } deviceAgentManagementService.checkAccessInfo(deviceIdentifier, testTaskSpec.accessKey); - return true; } } } diff --git a/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlobFileInfo.java b/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlobFileInfo.java index 4a95c3bfb..e56aee4cc 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlobFileInfo.java +++ b/common/src/main/java/com/microsoft/hydralab/common/entity/common/BlobFileInfo.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject; import com.microsoft.hydralab.common.util.HydraLabRuntimeException; import lombok.Data; +import org.springframework.http.HttpStatus; import org.springframework.util.DigestUtils; import javax.persistence.Column; @@ -55,9 +56,9 @@ public BlobFileInfo(File file, String relativePath, String fileType) { this.setMd5(DigestUtils.md5DigestAsHex(inputStream)); inputStream.close(); } catch (FileNotFoundException e) { - throw new HydraLabRuntimeException(500, "Generate temp file failed!", e); + throw new HydraLabRuntimeException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Generate temp file failed!", e); } catch (IOException e) { - throw new HydraLabRuntimeException(500, "Get the MD5 of temp file failed!", e); + throw new HydraLabRuntimeException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Get the MD5 of temp file failed!", e); } } diff --git a/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestRun.java b/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestRun.java index a1973604a..20619c885 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestRun.java +++ b/common/src/main/java/com/microsoft/hydralab/common/entity/common/TestRun.java @@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.microsoft.hydralab.ITestRun; +import com.microsoft.hydralab.agent.runner.ITestRun; import com.microsoft.hydralab.common.util.Const; import lombok.Data; import org.slf4j.Logger; diff --git a/common/src/main/java/com/microsoft/hydralab/common/util/AttachmentService.java b/common/src/main/java/com/microsoft/hydralab/common/util/AttachmentService.java index 25687b1bb..995af2926 100644 --- a/common/src/main/java/com/microsoft/hydralab/common/util/AttachmentService.java +++ b/common/src/main/java/com/microsoft/hydralab/common/util/AttachmentService.java @@ -244,7 +244,7 @@ public File verifyAndSaveFile(@NotNull MultipartFile originFile, String parentDi String fileSuffix = null; boolean isMatch = false; if (filename == null) { - throw new HydraLabRuntimeException(405, "error file type: " + filename); + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "error file type: " + filename); } if (fileTypes != null) { for (String fileType : fileTypes) { @@ -255,7 +255,7 @@ public File verifyAndSaveFile(@NotNull MultipartFile originFile, String parentDi } } if (!isMatch) { - throw new HydraLabRuntimeException(405, "error file type: " + filename); + throw new HydraLabRuntimeException(HttpStatus.BAD_REQUEST.value(), "error file type: " + filename); } } diff --git a/common/src/main/java/com/microsoft/hydralab/performance/PerformanceTestManagementService.java b/common/src/main/java/com/microsoft/hydralab/performance/PerformanceTestManagementService.java index e12b0b03b..d8a25e95c 100644 --- a/common/src/main/java/com/microsoft/hydralab/performance/PerformanceTestManagementService.java +++ b/common/src/main/java/com/microsoft/hydralab/performance/PerformanceTestManagementService.java @@ -1,6 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. package com.microsoft.hydralab.performance; -import com.microsoft.hydralab.ITestRun; +import com.microsoft.hydralab.agent.runner.ITestRun; +import com.microsoft.hydralab.agent.runner.TestRunThreadContext; import com.microsoft.hydralab.performance.inspectors.AndroidBatteryInfoInspector; import org.jetbrains.annotations.NotNull; import org.springframework.util.Assert; @@ -52,11 +55,10 @@ private static PerformanceTestResult createPerformanceTestResult(PerformanceInsp } /** - * TODO * @return the test run object from TestRunThreadContext */ private ITestRun getTestRun() { - return null; + return TestRunThreadContext.getTestRun(); } @Override diff --git a/gradle_plugin/README.md b/gradle_plugin/README.md index bcf6e258c..def2fd16e 100644 --- a/gradle_plugin/README.md +++ b/gradle_plugin/README.md @@ -3,14 +3,36 @@ This is the Gradle plugin of Hydra Lab. In order to simplify the onboarding procedure to Hydra Lab for any app, this project packaged the client util and made it an easy way for any app to leverage the cloud testing service of Hydra Lab. ## Prerequisite -### TODO +Include Hydra Lab plugin dependency in build.gradle of your project: +- Using the plugins DSL: +``` +plugins { + id "com.microsoft.hydralab.client-util" version "${plugin_version}" +} +``` +- Using legacy plugin application: +``` +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "com.microsoft.hydralab:gradle_plugin:${plugin_version}" + } +} + +apply plugin: "com.microsoft.hydralab.client-util" +``` +See [Release Notes](https://github.com/microsoft/HydraLab/wiki/Release-Notes) for latest and stable versions. ## Usage To trigger gradle task for Hydra Lab testing, simply follow below steps: -- Step 1: go to [template](link to template) page, copy the following files to your repo and modify the content: - - [build.gradle](link to template/build.gradle) +- Step 1: go to [template](https://github.com/microsoft/HydraLab/tree/main/gradle_plugin/src/main/resources/template) page, copy the following files to your repo and modify the content: + - [build.gradle](https://github.com/microsoft/HydraLab/blob/main/gradle_plugin/src/main/resources/template/build.gradle) - To introduce dependency on this plugin, please copy all content to repository/module you would like to use the plugin in. - - [gradle.properties](link to template/gradle.properties) + - [gradle.properties](https://github.com/microsoft/HydraLab/blob/main/gradle_plugin/src/main/resources/template/gradle.properties) - According to the comment inline and the running type you choose for your test, you should keep all required parameters and fill in them with correct values. - Step 2: Build your project/module to enable the Gradle plugin and task - Step 3: Run gradle task requestHydraLabTest @@ -20,3 +42,6 @@ To trigger gradle task for Hydra Lab testing, simply follow below steps: ## Known issue - Hard-coded with Azure DevOps embedded variable names, currently may not be compatible to other CI tools when fetching commit related information. + +## TODO +**- Add yml configuration file for task param setup.** diff --git a/sdk/src/main/java/com/microsoft/hydralab/ITestRun.java b/sdk/src/main/java/com/microsoft/hydralab/agent/runner/ITestRun.java similarity index 64% rename from sdk/src/main/java/com/microsoft/hydralab/ITestRun.java rename to sdk/src/main/java/com/microsoft/hydralab/agent/runner/ITestRun.java index e64d7dca1..762fc4173 100644 --- a/sdk/src/main/java/com/microsoft/hydralab/ITestRun.java +++ b/sdk/src/main/java/com/microsoft/hydralab/agent/runner/ITestRun.java @@ -1,4 +1,4 @@ -package com.microsoft.hydralab; +package com.microsoft.hydralab.agent.runner; import java.io.File; diff --git a/sdk/src/main/java/com/microsoft/hydralab/agent/runner/TestRunThreadContext.java b/sdk/src/main/java/com/microsoft/hydralab/agent/runner/TestRunThreadContext.java new file mode 100644 index 000000000..e226e6b1e --- /dev/null +++ b/sdk/src/main/java/com/microsoft/hydralab/agent/runner/TestRunThreadContext.java @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +package com.microsoft.hydralab.agent.runner; + +/** + * We will gradually deprecate ThreadParam and AppiumParam, and migrate to this. + * + */ +public class TestRunThreadContext { + private static final InheritableThreadLocal testRunThreadLocal = new InheritableThreadLocal<>(); + + /** + * Should be called in the TestRunner setup lifecycle + * @param testRun + */ + static void init(ITestRun testRun) { + clean(); + testRunThreadLocal.set(testRun); + } + + public static void clean() { + testRunThreadLocal.remove(); + } + + public static ITestRun getTestRun() { + return testRunThreadLocal.get(); + } +}
- +