Skip to content

Commit 69220de

Browse files
committed
Merge branch 'main' into zhoule/analysisSmartTestResult
2 parents ddf93f0 + 4528d2e commit 69220de

File tree

10 files changed

+98
-51
lines changed

10 files changed

+98
-51
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ehcache.xml @zhou9584 @olivershen-wow
1515
/android_client/ @lifesaver0129 @TedaLIEz @dexterdreeeam @taoran6
1616

1717
# TestTaskSpec
18-
TestTaskSpec.java @olivershen-wow @zhou9584 @dexterdreeeam
18+
/common/src/main/java/com/microsoft/hydralab/common/entity/ @olivershen-wow @zhou9584 @dexterdreeeam
1919

2020
# Gradle Plugin
2121
/gradle_plugin/ @olivershen-wow @taoran6 @dexterdreeeam

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
---
1414

15-
![HydraLabFeaturesPreview](docs/images/HydraLabFeaturesPreview.gif)
15+
https://github.com/microsoft/HydraLab/assets/8344245/cefefe24-4e11-4cc7-a3af-70cb44974735
1616

1717
[What is Hydra Lab?](#what-is) | [Get Started](#get-started) | [Who are using Hydra Lab?](#who-use-it) | [Contribute](#contribute) | [Contact Us](#contact) | [Links](#links) | [Wiki](https://github.com/microsoft/HydraLab/wiki)
1818
</div>

agent/src/main/java/com/microsoft/hydralab/agent/scheduled/ScheduledDeviceControlTasks.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void scheduledCheckWebSocketConnection() {
4343
agentWebSocketClient.reconnect();
4444
}
4545

46-
@Scheduled(cron = "0 10 6 ? * MON")
46+
@Scheduled(cron = "0 10 6 ? * *")
4747
public void scheduleCleanBuildSource() {
4848
logger.info("schedule clean build APK");
4949
clearFile(appOptions.getTestPackageLocation());

agent/src/main/resources/logback-common.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<!-- http://logback.qos.ch/codes.html#sat_missing_integer_token The %i conversion token is mandatory for size and time based archiving.
1616
In case the %i token is missing, SizeAndTimeBasedFNATP attached to RollingFileAppender will detect the omission and will not start. -->
1717
<fileNamePattern>./hydra/data/log/%d/hydra_lab.%d.%i.log</fileNamePattern>
18-
<maxHistory>30</maxHistory>
18+
<maxHistory>10</maxHistory>
1919
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
2020
<maxFileSize>10MB</maxFileSize>
2121
</timeBasedFileNamingAndTriggeringPolicy>
@@ -31,7 +31,7 @@
3131
<File>./hydra/data/access_log/hydra_lab_current.log</File>
3232
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
3333
<fileNamePattern>./hydra/data/access_log/%d/hydra_lab.%d.%i.log</fileNamePattern>
34-
<maxHistory>30</maxHistory>
34+
<maxHistory>10</maxHistory>
3535
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
3636
<maxFileSize>10MB</maxFileSize>
3737
</timeBasedFileNamingAndTriggeringPolicy>

android_client/app/build.gradle

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ android {
66

77
compileSdkVersion 33
88

9+
signingConfigs {
10+
debugSignConfig {
11+
keyAlias 'hydralab'
12+
keyPassword 'hydralab'
13+
storeFile file('../keystore.jks')
14+
storePassword 'hydralab'
15+
}
16+
}
17+
918
defaultConfig {
1019
applicationId "com.microsoft.hydralab.android.client"
1120
minSdkVersion 21
@@ -23,12 +32,12 @@ android {
2332

2433
buildTypes {
2534
debug {
26-
signingConfig signingConfigs.debug
35+
signingConfig signingConfigs.debugSignConfig
2736
minifyEnabled false
2837
}
2938

3039
release {
31-
signingConfig signingConfigs.debug
40+
signingConfig signingConfigs.debugSignConfig
3241
minifyEnabled false
3342
shrinkResources false
3443
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

android_client/keystore.jks

2.54 KB
Binary file not shown.

center/src/main/java/com/microsoft/hydralab/center/controller/TestTaskController.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,9 @@ public Result<Object> getTaskStatus(@CurrentSecurityContext SysUser requestor,
127127
}
128128
TestTask testTask = testDataService.getTestTaskDetail(testId);
129129
if (testTask != null) {
130-
if (!sysUserService.checkUserAdmin(requestor) && !userTeamManagementService.checkRequestorTeamRelation(requestor, testTask.getTeamId())) {
131-
return Result.error(HttpStatus.UNAUTHORIZED.value(), "Unauthorized, the TestTask doesn't belong to user's Teams");
132-
}
133-
130+
// if (!sysUserService.checkUserAdmin(requestor) && !userTeamManagementService.checkRequestorTeamRelation(requestor, testTask.getTeamId())) {
131+
// return Result.error(HttpStatus.UNAUTHORIZED.value(), "Unauthorized, the TestTask doesn't belong to user's Teams");
132+
// }
134133
return Result.ok(testTask);
135134
}
136135
TestTaskQueuedInfo queuedInfo = testTaskService.getTestQueuedInfo(testId);

center/src/main/java/com/microsoft/hydralab/center/service/TestDataService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ public void saveTestRunGPTSuggestion(TestRun testRun, String suggestion) {
271271
public void saveTestCaseGPTSuggestion(AndroidTestUnit testCase, String suggestion) {
272272
testCase.setSuggestion(suggestion);
273273
androidTestUnitRepository.save(testCase);
274+
keyValueRepository.saveAndroidTestUnit(testCase);
274275
}
275276

276277
public TestRun findTestRunById(String testRunId) {

common/src/main/java/com/microsoft/hydralab/common/management/AppiumServerManager.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
3+
34
package com.microsoft.hydralab.common.management;
45

56
import com.microsoft.hydralab.common.entity.common.DeviceInfo;
@@ -35,22 +36,24 @@
3536
import java.net.MalformedURLException;
3637
import java.net.URL;
3738
import java.time.Duration;
39+
import java.util.Date;
3840
import java.util.Map;
3941
import java.util.Objects;
4042
import java.util.concurrent.ConcurrentHashMap;
4143
import java.util.concurrent.TimeUnit;
4244

43-
4445
public class AppiumServerManager {
4546
public static final String EDGE_DRIVER_DOWNLOAD_URL = "https://msedgedriver.azureedge.net/";
4647
public static final String EDGE_DRIVER_ZIP = "edgedriver_win64.zip";
4748
public static final String EDGE_DRIVER_EXE = "msedgedriver.exe";
4849
public static final String EDGE_DRIVER_VERSION_TXT = "msedgedriverversion.txt";
4950
public static final String EDGE_PROCESS_NAME = "msedge";
5051
public static final String WINDOWS_HANDLE_BY_APP_FAMILY_ID_SCRIPT_NAME = "WindowsAppIdToHandle.ps1";
52+
private static final int DRIVER_EXPIRED_TIME = 1000 * 60 * 60 * 24;
5153
private final Map<String, IOSDriver> iOSDrivers = new ConcurrentHashMap<>();
5254
private final Map<String, AndroidDriver> androidDrivers = new ConcurrentHashMap<>();
5355
private final Map<String, WindowsDriver> windowsAppDrivers = new ConcurrentHashMap<>();
56+
private final Map<String, Date> driverCreateTime = new ConcurrentHashMap<>();
5457
private AppiumDriverLocalService service;
5558
private int appiumServerPort = 10086;
5659
private String appiumServerHost = "127.0.0.1";
@@ -111,7 +114,16 @@ public IOSDriver getIOSDriver(DeviceInfo deviceInfo, Logger logger) {
111114
if (iosDriver != null && isDriverAlive(iosDriver)) {
112115
logger.info(iosDriver.toString());
113116
logger.info(iosDriver.getStatus().toString());
114-
return iosDriver;
117+
if (isDriverExpired(deviceInfo)) {
118+
try {
119+
logger.info("driver expired, quit old driver and create a new one");
120+
quitIOSDriver(deviceInfo, logger);
121+
} catch (Exception e) {
122+
logger.error("quit old driver failed", e);
123+
}
124+
} else {
125+
return iosDriver;
126+
}
115127
}
116128

117129
int wdaPort = IOSUtils.getWdaPortByUdid(udid, logger);
@@ -150,6 +162,7 @@ public IOSDriver getIOSDriver(DeviceInfo deviceInfo, Logger logger) {
150162

151163
logger.info("Create Driver, SessionID: " + iosDriver.getSessionId());
152164
iOSDrivers.put(udid, iosDriver);
165+
driverCreateTime.put(udid, new Date());
153166
sessionCreated = true;
154167
} catch (MalformedURLException e) {
155168
throw new RuntimeException(e);
@@ -245,7 +258,9 @@ private String getHexAppTopLevelWindowByFamilyName(String appFamilyName, Logger
245258

246259
@Nonnull
247260
private String getHexAppTopLevelWindowByProcessName(String processName, Logger logger) {
248-
String processInfo = ShellUtils.execLocalCommandWithResult(ShellUtils.POWER_SHELL_PATH + " -Command " + "\"(Get-Process | where {$_.mainWindowTitle -and $_.mainWindowHandle -ne 0 -and $_.Name -eq '" + processName + "'} | Select mainWindowHandle).mainWindowHandle\"", logger);
261+
String processInfo = ShellUtils.execLocalCommandWithResult(ShellUtils.POWER_SHELL_PATH + " -Command " +
262+
"\"(Get-Process | where {$_.mainWindowTitle -and $_.mainWindowHandle -ne 0 -and $_.Name -eq '" +
263+
processName + "'} | Select mainWindowHandle).mainWindowHandle\"", logger);
249264
logger.info(processName + " processInfo: " + processInfo);
250265
if (processInfo != null && processInfo.length() > 0) {
251266
String handlerIdStr = processInfo.trim().split(" ")[0];
@@ -296,6 +311,14 @@ public Boolean isDriverAlive(IOSDriver driver) {
296311
}
297312
}
298313

314+
public Boolean isDriverExpired(DeviceInfo deviceInfo) {
315+
Date date = driverCreateTime.get(deviceInfo.getSerialNum());
316+
if (date == null || new Date().getTime() - date.getTime() < DRIVER_EXPIRED_TIME) {
317+
return false;
318+
}
319+
return true;
320+
}
321+
299322
public Boolean isDriverAlive(WindowsDriver driver) {
300323
try {
301324
driver.getScreenshotAs(OutputType.FILE);
@@ -312,7 +335,6 @@ public void setWorkspacePath(String path) {
312335
edgeDriverVersionFile = new File(workspacePath, EDGE_DRIVER_VERSION_TXT).getAbsolutePath();
313336
}
314337

315-
316338
public WindowsDriver getWindowsEdgeDriver(Logger logger) {
317339
startAppiumServer();
318340

@@ -404,7 +426,6 @@ public void forceKillEdgeDriver() {
404426

405427
}
406428

407-
408429
public void quitIOSDriver(DeviceInfo deviceInfo, Logger logger) {
409430
String udid = deviceInfo.getSerialNum();
410431
logger.info("Quitting the driver for device: " + udid);
@@ -422,7 +443,7 @@ public void quitIOSDriver(DeviceInfo deviceInfo, Logger logger) {
422443
}
423444
}
424445
iOSDrivers.remove(udid);
425-
446+
driverCreateTime.remove(udid);
426447
}
427448

428449
public void quitAndroidDriver(DeviceInfo deviceInfo, Logger logger) {

react/src/component/TasksView.jsx

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ class TasksView extends BaseView {
144144
<StyledTableCell key={'Timestamp'} align="center">
145145
<ThemeProvider theme={darkTheme}>
146146
<FormControl className="ml-0" fullWidth={true}>
147-
<InputLabel id="end-time-range-select-label">End Time Range</InputLabel>
147+
<InputLabel id="start-time-range-select-label">Start Time Range</InputLabel>
148148
<Select
149-
labelId="end-time-range-select-label"
150-
id="end-time-range-select"
151-
label="End Time Range"
149+
labelId="start-time-range-select-label"
150+
id="start-time-range-select"
151+
label="Start Time Range"
152152
size="small"
153153
value={selectedParams.time}
154154
onChange={this.selectTimeChange}
@@ -677,26 +677,7 @@ class TasksView extends BaseView {
677677
this.handleStatus("openTestDetail", false)
678678
}
679679

680-
queryTask() {
681-
console.log(this.state.selectedParams)
682-
let queryParams = [
683-
{
684-
"key": "status",
685-
"op": "ne",
686-
"value": "running"
687-
},
688-
{
689-
"key": "runningType",
690-
"op": "in",
691-
"value": this.state.selectedParams.TestType.length > 0 ? this.state.selectedParams.TestType : params.TestType
692-
},
693-
{
694-
"key": "type",
695-
"op": "in",
696-
"value": this.state.selectedParams.TriggerType
697-
}
698-
]
699-
680+
taskParamUpdate(queryParams) {
700681
if (this.state.selectedParams.suite !== '') {
701682
queryParams.push({
702683
"key": "testSuite",
@@ -745,6 +726,29 @@ class TasksView extends BaseView {
745726
"dateFormatString": "yyyy-MM-dd HH:mm:ss.S"
746727
})
747728
}
729+
}
730+
731+
queryTask() {
732+
console.log(this.state.selectedParams)
733+
// completed tasks
734+
let queryParams = [
735+
{
736+
"key": "status",
737+
"op": "ne",
738+
"value": "running"
739+
},
740+
{
741+
"key": "runningType",
742+
"op": "in",
743+
"value": this.state.selectedParams.TestType.length > 0 ? this.state.selectedParams.TestType : params.TestType
744+
},
745+
{
746+
"key": "type",
747+
"op": "in",
748+
"value": this.state.selectedParams.TriggerType
749+
}
750+
]
751+
this.taskParamUpdate(queryParams)
748752

749753
let postBody = {
750754
'page': this.state.page - 1,
@@ -760,18 +764,9 @@ class TasksView extends BaseView {
760764
})
761765

762766
}, postBody, null, null, null)
763-
}
764-
765-
componentDidMount() {
766-
console.log(this.props)
767-
this.setState({
768-
hideSkeleton: false,
769-
})
770-
771-
this.queryTask()
772767

773768
if (this.state.page === 1) {
774-
769+
// queued tasks
775770
axios.get('/api/test/task/queue').then(res => {
776771
if (res.data && res.data.code === 200) {
777772
if (res.data.content) {
@@ -785,13 +780,26 @@ class TasksView extends BaseView {
785780
}
786781
}).catch(this.snackBarError)
787782

783+
// running tasks
788784
let queryParams = [
789785
{
790786
"key": "status",
791787
"op": "equal",
792788
"value": "running"
789+
},
790+
{
791+
"key": "runningType",
792+
"op": "in",
793+
"value": this.state.selectedParams.TestType.length > 0 ? this.state.selectedParams.TestType : params.TestType
794+
},
795+
{
796+
"key": "type",
797+
"op": "in",
798+
"value": this.state.selectedParams.TriggerType
793799
}
794800
]
801+
this.taskParamUpdate(queryParams)
802+
795803
let postBody = {
796804
'page': 0,
797805
'pageSize': -1,
@@ -808,6 +816,15 @@ class TasksView extends BaseView {
808816
}
809817
}
810818

819+
componentDidMount() {
820+
console.log(this.props)
821+
this.setState({
822+
hideSkeleton: false,
823+
})
824+
825+
this.queryTask()
826+
}
827+
811828
componentWillUnmount() {
812829
// cancel requests
813830
}

0 commit comments

Comments
 (0)