Skip to content

Commit a56c7c3

Browse files
authored
Merge pull request #25 from snieguu/master
Version 2.62.0, TD-10862, use new test run creator api & cleanup
2 parents b9268db + c1ac5e6 commit a56c7c3

File tree

5 files changed

+132
-122
lines changed

5 files changed

+132
-122
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ repo
66
build
77
.gradle
88
.idea
9+
!.idea/codeStyleSettings.xml
910
local.properties

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Below is listed all the supported configurations parameters:
5050

5151
cloudUrl = 'https://cloud.testdroid.com' //optional - default live
5252
projectName "Project 1" //optional - default: create a new project
53-
mode "FULL_RUN" //FULL_RUN / APP_CRAWLER / UI_AUTOMATOR - deprecated, mode is set based on project type
53+
mode "FULL_RUN" //FULL_RUN / APP_CRAWLER / UI_AUTOMATOR
5454
testRunName "Custom test run name" //optional - default: build variant name
5555

5656
deviceLanguageCode "en-US" //optional - locale <ISO 63>_<ISO 3166> default: en-US

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ dependencies {
1818
groovy localGroovy()
1919

2020
compile 'com.android.tools.build:builder-test-api:2.3.0'
21-
compile 'com.testdroid:testdroid-api:2.49'
21+
compile 'com.testdroid:testdroid-api:2.62'
2222
testCompile 'junit:junit:3.8.1'
2323
testCompile 'com.android.tools.build:gradle:1.1.0'
2424

2525
}
2626

2727
group = 'com.testdroid'
2828
archivesBaseName = 'gradle'
29-
version = '2.49.1'
29+
version = '2.62.0'
3030

3131
// custom tasks for creating source/javadoc jars
3232
task sourcesJar(type: Jar, dependsOn:classes) {

src/main/groovy/com/testdroid/TestDroidExtension.groovy

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ class TestDroidExtension {
2727
String apiKey
2828
String projectName
2929
String cloudUrl
30-
@Deprecated
31-
String mode
30+
Mode mode = Mode.FULL_RUN
3231
String deviceGroup
3332
String deviceLanguageCode
3433
String hookUrl
@@ -86,5 +85,11 @@ class TestDroidExtension {
8685
OAUTH2
8786
}
8887

88+
enum Mode {
89+
APP_CRAWLER,
90+
FULL_RUN,
91+
UI_AUTOMATOR,
92+
}
93+
8994
}
9095

src/main/groovy/com/testdroid/TestDroidServer.java

Lines changed: 121 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,44 @@
1919
import com.android.annotations.NonNull;
2020
import com.android.annotations.Nullable;
2121
import com.android.builder.testing.api.TestServer;
22-
import com.testdroid.api.*;
22+
import com.testdroid.api.APIClient;
23+
import com.testdroid.api.APIException;
24+
import com.testdroid.api.APIKeyClient;
25+
import com.testdroid.api.DefaultAPIClient;
26+
import com.testdroid.api.dto.Context;
27+
import com.testdroid.api.filter.BooleanFilterEntry;
28+
import com.testdroid.api.filter.StringFilterEntry;
2329
import com.testdroid.api.model.*;
2430
import org.apache.commons.lang.StringUtils;
2531
import org.apache.http.HttpHost;
2632
import org.gradle.api.InvalidUserDataException;
2733
import org.gradle.api.logging.Logger;
2834

2935
import java.io.File;
36+
import java.util.ArrayList;
37+
import java.util.Collections;
3038
import java.util.List;
3139

3240
import static com.testdroid.TestDroidExtension.Authorization.APIKEY;
3341
import static com.testdroid.TestDroidExtension.Authorization.OAUTH2;
42+
import static com.testdroid.api.dto.Operand.EQ;
43+
import static com.testdroid.api.model.APIFileConfig.Action.INSTALL;
44+
import static com.testdroid.api.model.APIFileConfig.Action.RUN_TEST;
45+
import static com.testdroid.api.model.APIProject.Type.ANDROID;
46+
import static com.testdroid.dao.repository.dto.MappingKey.*;
47+
import static java.lang.Boolean.TRUE;
48+
import static java.lang.Integer.MAX_VALUE;
49+
import static org.apache.commons.lang3.StringUtils.EMPTY;
3450

3551
public class TestDroidServer extends TestServer {
3652

3753
private final TestDroidExtension extension;
54+
3855
private final Logger logger;
56+
3957
private static final String CLOUD_URL = "https://cloud.testdroid.com";
4058

41-
TestDroidServer(@NonNull TestDroidExtension extension,
42-
@NonNull Logger logger) {
59+
TestDroidServer(@NonNull TestDroidExtension extension, @NonNull Logger logger) {
4360
this.extension = extension;
4461
this.logger = logger;
4562
}
@@ -49,49 +66,6 @@ public String getName() {
4966
return "testdroid";
5067
}
5168

52-
private APIProject searchProject(String projectName, APIListResource<APIProject> projectList) throws APIException {
53-
if (projectList == null || projectList.getTotal() == 0 || projectList.getEntity() == null ||
54-
projectList.getEntity().getData() == null) {
55-
return null;
56-
}
57-
58-
do {
59-
60-
List<APIProject> projects = projectList.getEntity().getData();
61-
for (APIProject project : projects) {
62-
if (projectName.equals(project.getName())) {
63-
return project;
64-
}
65-
}
66-
67-
projectList = projectList.getNext();
68-
} while (projectList != null);
69-
70-
return null;
71-
}
72-
73-
private APIDeviceGroup searchDeviceGroup(String deviceGroupName, APIListResource<APIDeviceGroup> deviceGroupList) throws APIException {
74-
if (deviceGroupList == null || deviceGroupList.getTotal() == 0 || deviceGroupList.getEntity() == null ||
75-
deviceGroupList.getEntity().getData() == null) {
76-
77-
return null;
78-
}
79-
80-
do {
81-
List<APIDeviceGroup> deviceGroups = deviceGroupList.getEntity().getData();
82-
for (APIDeviceGroup deviceGroup : deviceGroups) {
83-
84-
if (deviceGroupName.equals(deviceGroup.getDisplayName())) {
85-
return deviceGroup;
86-
}
87-
}
88-
89-
deviceGroupList = deviceGroupList.getNext();
90-
} while (deviceGroupList != null);
91-
92-
return null;
93-
}
94-
9569
@Override
9670
public void uploadApks(@NonNull String variantName, @NonNull File testApk, @Nullable File testedApk) {
9771
APIUser user;
@@ -116,47 +90,49 @@ public void uploadApks(@NonNull String variantName, @NonNull File testApk, @Null
11690
try {
11791
if (extension.getProjectName() == null) {
11892
logger.warn("TESTDROID: Project name is not set - creating a new one");
119-
project = user.createProject(APIProject.Type.ANDROID);
93+
project = user.createProject(ANDROID);
12094
logger.info("TESTDROID: Created project:" + project.getName());
12195
} else {
122-
APIListResource<APIProject> projectList;
123-
projectList = user.getProjectsResource();
124-
125-
project = searchProject(extension.getProjectName(), projectList);
126-
if (project == null) {
127-
throw new InvalidUserDataException("TESTDROID: Can't find project " + extension.getProjectName());
128-
}
129-
96+
final Context<APIProject> context = new Context(APIProject.class, 0, MAX_VALUE, EMPTY, EMPTY);
97+
context.addFilter(new StringFilterEntry(NAME, EQ, extension.getProjectName()));
98+
project = user.getProjectsResource(context).getEntity().getData().stream().findFirst()
99+
.orElseThrow(() -> new InvalidUserDataException("TESTDROID: Can't find project " + extension
100+
.getProjectName()));
130101
}
131-
//reload
132-
project = user.getProject(project.getId());
133102
logger.info(project.getName());
134103

135-
APIListResource<APIDeviceGroup> deviceGroupsResource = user.getDeviceGroupsResource();
136-
APIDeviceGroup deviceGroup = searchDeviceGroup(extension.getDeviceGroup(), deviceGroupsResource);
104+
final Context<APIDeviceGroup> context = new Context(APIDeviceGroup.class, 0, MAX_VALUE, EMPTY, EMPTY);
105+
context.setExtraParams(Collections.singletonMap(WITH_PUBLIC, TRUE));
106+
context.addFilter(new StringFilterEntry(DISPLAY_NAME, EQ, extension.getDeviceGroup()));
137107

138-
if (deviceGroup == null) {
139-
throw new InvalidUserDataException("TESTDROID: Can't find device group " + extension.getDeviceGroup());
140-
} else if (deviceGroup.getDeviceCount() == 0) {
141-
throw new InvalidUserDataException("TESTDROID: There is no devices in group:" + extension.getDeviceGroup());
108+
APIDeviceGroup deviceGroup = user.getDeviceGroupsResource(context).getEntity().getData().stream()
109+
.findFirst()
110+
.orElseThrow(() -> new InvalidUserDataException("TESTDROID: Can't find device group " + extension
111+
.getDeviceGroup()));
112+
113+
if (deviceGroup.getDeviceCount() == 0) {
114+
throw new InvalidUserDataException("TESTDROID: There is no devices in group:" + extension
115+
.getDeviceGroup());
142116
}
143117

144-
updateAPITestRunConfigValues(project, extension, deviceGroup.getId());
118+
APITestRunConfig testRunConfig = project.getTestRunConfig();
119+
updateAPITestRunConfigValues(user, testRunConfig, extension, deviceGroup.getId());
145120

146121
logger.info("TESTDROID: Uploading apks into project {} (id:{})", project.getName(), project.getId());
147122
File instrumentationAPK = testApk;
148123

149-
if (extension.getFullRunConfig() != null && extension.getFullRunConfig().getInstrumentationAPKPath() != null
124+
if (extension.getFullRunConfig().getInstrumentationAPKPath() != null
150125
&& new File(extension.getFullRunConfig().getInstrumentationAPKPath()).exists()) {
151-
152126
instrumentationAPK = new File(extension.getFullRunConfig().getInstrumentationAPKPath());
153-
logger.info("TESTDROID: Using custom path for instrumentation APK: {}", extension.getFullRunConfig().getInstrumentationAPKPath());
127+
logger.info("TESTDROID: Using custom path for instrumentation APK: {}", extension.getFullRunConfig()
128+
.getInstrumentationAPKPath());
154129
}
155-
uploadBinaries(project, instrumentationAPK, testedApk);
156-
157-
APITestRun apiTestRun = project.run(extension.getTestRunName() == null ? variantName : extension.getTestRunName());
158-
extension.setTestRunId(String.valueOf(apiTestRun.getId()));
159-
extension.setProjectId(String.valueOf(apiTestRun.getProjectId()));
130+
List<APIFileConfig> apiFileConfigs = uploadBinaries(user, instrumentationAPK, testedApk);
131+
testRunConfig.setFiles(apiFileConfigs);
132+
testRunConfig.setTestRunName(extension.getTestRunName() == null ? variantName : extension.getTestRunName());
133+
APITestRun testRun = user.startTestRun(testRunConfig);
134+
extension.setTestRunId(String.valueOf(testRun.getId()));
135+
extension.setProjectId(String.valueOf(testRun.getProjectId()));
160136

161137
} catch (APIException exc) {
162138
throw new InvalidUserDataException("TESTDROID: Uploading failed", exc);
@@ -178,13 +154,16 @@ private APIClient createAPIClient(String testdroidCloudURL, TestDroidExtension.A
178154
case APIKEY_PROXY:
179155
return new APIKeyClient(testdroidCloudURL, extension.getApiKey(), buildProxyHost(), false);
180156
case APIKEY_PROXY_CREDENTIALS:
181-
return new APIKeyClient(testdroidCloudURL, extension.getApiKey(), buildProxyHost(), proxyUser, proxyPassword, false);
157+
return new APIKeyClient(testdroidCloudURL, extension
158+
.getApiKey(), buildProxyHost(), proxyUser, proxyPassword, false);
182159
case OAUTH:
183160
return new DefaultAPIClient(testdroidCloudURL, extension.getUsername(), extension.getPassword());
184161
case OAUTH_PROXY:
185-
return new DefaultAPIClient(testdroidCloudURL, extension.getUsername(), extension.getPassword(), buildProxyHost(), false);
162+
return new DefaultAPIClient(testdroidCloudURL, extension.getUsername(), extension
163+
.getPassword(), buildProxyHost(), false);
186164
case OAUTH_PROXY_CREDENTIALS:
187-
return new DefaultAPIClient(testdroidCloudURL, extension.getUsername(), extension.getPassword(), buildProxyHost(), proxyUser, proxyPassword, false);
165+
return new DefaultAPIClient(testdroidCloudURL, extension.getUsername(), extension
166+
.getPassword(), buildProxyHost(), proxyUser, proxyPassword, false);
188167
case UNSUPPORTED:
189168
default:
190169
return null;
@@ -203,58 +182,63 @@ private HttpHost buildProxyHost() {
203182
return new HttpHost(proxyHost, port);
204183
}
205184

206-
private void uploadBinaries(APIProject project, File testApk, File testedApk) throws APIException {
207-
208-
if (project.getType().equals(APIProject.Type.UIAUTOMATOR)) {
209-
210-
if (extension.getUiAutomatorTestConfig() == null || extension.getUiAutomatorTestConfig().getUiAutomatorJarPath() == null) {
211-
throw new APIException("TESTDROID: Configure uiautomator settings");
212-
}
213-
File jarFile = new File(extension.getUiAutomatorTestConfig().getUiAutomatorJarPath());
214-
if (!jarFile.exists()) {
215-
throw new APIException("TESTDROID: Invalid uiAutomator jar file:" + jarFile.getAbsolutePath());
216-
}
217-
project.uploadTest(new File(extension.getUiAutomatorTestConfig().getUiAutomatorJarPath()), "application/octet-stream");
218-
logger.info("TESTDROID: uiautomator file uploaded");
219-
project.uploadApplication(testedApk, "application/octet-stream");
185+
private List<APIFileConfig> uploadBinaries(APIUser user, File testApk, File testedApk)
186+
throws APIException, InvalidUserDataException {
187+
List<APIFileConfig> files = new ArrayList<>();
188+
APIProjectJobConfig.Type type = resolveFrameworkType(extension);
189+
if (testedApk != null && testedApk.exists()) {
190+
files.add(new APIFileConfig(user.uploadFile(testedApk).getId(), INSTALL));
220191
logger.info("TESTDROID: Android application uploaded");
221-
} else {
222-
223-
if (testedApk != null && testedApk.exists()) {
224-
project.uploadApplication(testedApk, "application/octet-stream");
225-
logger.info("TESTDROID: Android application uploaded");
226-
} else {
227-
logger.warn("TESTDROID: Target application has not been added - uploading only test apk ");
228-
}
229-
230-
if (testApk != null && APIProject.Type.ANDROID == project.getType()) {
231-
project.uploadTest(testApk, "application/octet-stream");
232-
logger.info("TESTDROID: Android test uploaded");
233-
}
234192
}
235-
193+
switch (type) {
194+
case INSTATEST:
195+
break;
196+
case DEFAULT:
197+
if (testApk != null && testApk.exists()) {
198+
files.add(new APIFileConfig(user.uploadFile(testApk).getId(), RUN_TEST));
199+
logger.info("TESTDROID: Android test uploaded");
200+
}
201+
break;
202+
case UIAUTOMATOR:
203+
if (extension.getUiAutomatorTestConfig().getUiAutomatorJarPath() == null) {
204+
throw new APIException("TESTDROID: Configure uiautomator settings");
205+
}
206+
File jarFile = new File(extension.getUiAutomatorTestConfig().getUiAutomatorJarPath());
207+
if (jarFile.exists()) {
208+
files.add(new APIFileConfig(user.uploadFile(jarFile).getId(), RUN_TEST));
209+
logger.info("TESTDROID: uiautomator file uploaded");
210+
} else {
211+
throw new InvalidUserDataException("TESTDROID: Invalid uiAutomator jar file:" + jarFile
212+
.getAbsolutePath());
213+
}
214+
break;
215+
default:
216+
}
217+
return files;
236218
}
237219

238-
239-
240-
private APITestRunConfig updateAPITestRunConfigValues(APIProject project, TestDroidExtension extension, Long deviceGroupId) throws APIException {
241-
242-
APITestRunConfig config = project.getTestRunConfig();
220+
private APITestRunConfig updateAPITestRunConfigValues(
221+
APIUser user, APITestRunConfig config, TestDroidExtension extension, Long deviceGroupId)
222+
throws APIException {
243223

244224
config.setHookURL(extension.getHookUrl());
245225
config.setDeviceLanguageCode(extension.getDeviceLanguageCode());
246-
config.setScheduler(extension.getScheduler() != null ? APITestRunConfig.Scheduler.valueOf(extension.getScheduler()) : null);
247-
if (extension.getMode() != null) {
248-
logger.warn("TESTDROID: mode variable is not used anymore");
226+
if (extension.getScheduler() != null) {
227+
config.setScheduler(APITestRunConfig.Scheduler.valueOf(extension.getScheduler()));
249228
}
250229

230+
APIProjectJobConfig.Type type = resolveFrameworkType(extension);
231+
config.setFrameworkId(resolveFrameworkId(user, type));
232+
config.setOsType(APIDevice.OsType.ANDROID);
233+
251234
//App crawler settings
252235
config.setApplicationUsername(extension.getAppCrawlerConfig().getApplicationUserName());
253236
config.setApplicationPassword(extension.getAppCrawlerConfig().getApplicationPassword());
254237

255238
//Full run settings
256239
if (extension.getFullRunConfig().getLimitationType() != null) {
257-
config.setLimitationType(APITestRunConfig.LimitationType.valueOf(extension.getFullRunConfig().getLimitationType()));
240+
config.setLimitationType(APITestRunConfig.LimitationType
241+
.valueOf(extension.getFullRunConfig().getLimitationType()));
258242
config.setLimitationValue(extension.getFullRunConfig().getLimitationValue());
259243
}
260244

@@ -263,13 +247,36 @@ private APITestRunConfig updateAPITestRunConfigValues(APIProject project, TestDr
263247
config.setScreenshotDir(extension.getTestScreenshotDir());
264248
config.setInstrumentationRunner(extension.getFullRunConfig().getInstrumentationRunner());
265249
config.setUsedDeviceGroupId(deviceGroupId);
250+
//Reset as in Gradle Plugin we use only deviceGroups
251+
config.setDeviceIds(null);
266252
//Ui automator settings
267253
config.setUiAutomatorTestClasses(extension.getUiAutomatorTestConfig().getUiAutomatorTestClasses());
268-
269-
config.update();
270254
return config;
271255

256+
}
257+
258+
private APIProjectJobConfig.Type resolveFrameworkType(TestDroidExtension extension) {
259+
switch (extension.getMode()) {
260+
case FULL_RUN:
261+
return APIProjectJobConfig.Type.DEFAULT;
262+
case UI_AUTOMATOR:
263+
return APIProjectJobConfig.Type.UIAUTOMATOR;
264+
case APP_CRAWLER:
265+
default:
266+
return APIProjectJobConfig.Type.INSTATEST;
267+
}
268+
}
272269

270+
private Long resolveFrameworkId(APIUser user, APIProjectJobConfig.Type type) throws APIException {
271+
final Context<APIFramework> context = new Context(APIFramework.class, 0, MAX_VALUE, EMPTY, EMPTY);
272+
context.addFilter(new StringFilterEntry(OS_TYPE, EQ, ANDROID.name()));
273+
context.addFilter(new BooleanFilterEntry(FOR_PROJECTS, EQ, TRUE));
274+
context.addFilter(new BooleanFilterEntry(CAN_RUN_FROM_UI, EQ, TRUE));
275+
context.addFilter(new StringFilterEntry(TYPE, EQ, type.name()));
276+
return user.getAvailableFrameworksResource(context).getEntity().getData().stream().findFirst()
277+
.map(APIFramework::getId)
278+
.orElseThrow(() -> new InvalidUserDataException("TESTDROID: Can't determinate framework for " +
279+
extension.getProjectName()));
273280
}
274281

275282
@Override
@@ -289,9 +296,6 @@ public boolean isConfigured() {
289296
if (extension.getProjectName() == null) {
290297
logger.warn("TESTDROID: project name has not been set, creating a new project");
291298
}
292-
if (extension.getMode() != null) {
293-
logger.warn("TESTDROID: mode variable is not used anymore");
294-
}
295299
if (extension.getDeviceGroup() == null) {
296300
logger.warn("TESTDROID: Device group has not been set");
297301
return false;

0 commit comments

Comments
 (0)