1919import com .android .annotations .NonNull ;
2020import com .android .annotations .Nullable ;
2121import 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 ;
2329import com .testdroid .api .model .*;
2430import org .apache .commons .lang .StringUtils ;
2531import org .apache .http .HttpHost ;
2632import org .gradle .api .InvalidUserDataException ;
2733import org .gradle .api .logging .Logger ;
2834
2935import java .io .File ;
36+ import java .util .ArrayList ;
37+ import java .util .Collections ;
3038import java .util .List ;
3139
3240import static com .testdroid .TestDroidExtension .Authorization .APIKEY ;
3341import 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
3551public 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