1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.simpligility.maven.plugins.android.standalonemojos;
18
19 import java.io.File;
20 import java.io.IOException;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.apache.maven.plugin.MojoExecutionException;
24 import org.apache.maven.plugin.MojoFailureException;
25 import org.apache.maven.plugins.annotations.Mojo;
26 import org.apache.maven.plugins.annotations.Parameter;
27
28 import com.android.ddmlib.AdbCommandRejectedException;
29 import com.android.ddmlib.IDevice;
30 import com.android.ddmlib.ShellCommandUnresponsiveException;
31 import com.android.ddmlib.TimeoutException;
32 import com.android.ddmlib.testrunner.UIAutomatorRemoteAndroidTestRunner;
33 import com.simpligility.maven.plugins.android.AbstractAndroidMojo;
34 import com.simpligility.maven.plugins.android.AndroidTestRunListener;
35 import com.simpligility.maven.plugins.android.DeviceCallback;
36 import com.simpligility.maven.plugins.android.ScreenshotServiceWrapper;
37 import com.simpligility.maven.plugins.android.common.DeviceHelper;
38 import com.simpligility.maven.plugins.android.config.ConfigHandler;
39 import com.simpligility.maven.plugins.android.config.ConfigPojo;
40 import com.simpligility.maven.plugins.android.config.PullParameter;
41 import com.simpligility.maven.plugins.android.configuration.UIAutomator;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 @SuppressWarnings( "unused" )
64 @Mojo( name = "uiautomator", requiresProject = false )
65 public class UIAutomatorMojo extends AbstractAndroidMojo
66 {
67
68
69
70 @Parameter( property = "maven.test.skip", defaultValue = "false", readonly = true )
71 private boolean mavenTestSkip;
72
73
74
75
76 @Parameter( property = "skipTests", defaultValue = "false", readonly = true )
77 private boolean mavenSkipTests;
78
79
80
81
82
83 @Parameter( property = "maven.test.failure.ignore", defaultValue = "false", readonly = true )
84 private boolean mavenTestFailureIgnore;
85
86
87
88
89
90 @Parameter( property = "testFailureIgnore", defaultValue = "false", readonly = true )
91 private boolean mavenIgnoreTestFailure;
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 @Parameter
125 @ConfigPojo
126 private UIAutomator uiautomator;
127
128
129
130
131
132 @Parameter( property = "android.uiautomator.skip" )
133 private Boolean uiautomatorSkip;
134
135 @PullParameter( defaultValue = "true" )
136 private Boolean parsedSkip;
137
138
139
140
141 @Parameter( property = "android.uiautomator.jarFile" )
142 private String uiautomatorJarFile;
143
144 @PullParameter( defaultValueGetterMethod = "getJarFile" )
145 private String parsedJarFile;
146
147
148
149
150
151
152
153
154
155 @Parameter( property = "android.uiautomator.testClassOrMethod" )
156 private String[] uiautomatorTestClassOrMethods;
157
158 @PullParameter( required = false, defaultValueGetterMethod = "getTestClassOrMethods" )
159 private String[] parsedTestClassOrMethods;
160
161
162
163
164
165 @Parameter( property = "android.uiautomator.noHup" )
166 private Boolean uiautomatorNoHup;
167
168 @PullParameter( defaultValue = "false" )
169 private Boolean parsedNoHup;
170
171
172
173
174 @Parameter( property = "android.uiautomator.debug" )
175 private Boolean uiautomatorDebug = false;
176
177 @PullParameter( defaultValue = "false" )
178 private Boolean parsedDebug;
179
180
181
182
183 @Parameter( property = "android.uiautomator.useDump" )
184 private Boolean uiautomatorUseDump;
185
186 @PullParameter( defaultValue = "false" )
187 private Boolean parsedUseDump;
188
189
190
191
192
193 @Parameter( property = "android.uiautomator.dumpFilePath" )
194 private String uiautomatorDumpFilePath;
195
196 @PullParameter( required = false, defaultValue = "/storage/sdcard0/window_dump.xml" )
197 private String parsedDumpFilePath;
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 @Parameter( property = "android.uiautomator.createReport" )
216 private Boolean uiautomatorCreateReport;
217
218 @PullParameter( defaultValue = "false" )
219 private Boolean parsedCreateReport;
220
221
222
223
224
225
226
227 @Parameter( property = "android.uiautomator.reportSuffix" )
228 private String uiautomatorReportSuffix;
229
230 @PullParameter( required = false, defaultValueGetterMethod = "getReportSuffix" )
231 private String parsedReportSuffix;
232
233
234
235
236
237 @Parameter( property = "android.uiautomator.takeScreenshotOnFailure" )
238 private Boolean uiautomatorTakeScreenshotOnFailure;
239
240 @PullParameter( defaultValue = "false" )
241 private Boolean parsedTakeScreenshotOnFailure;
242
243
244
245
246
247 @Parameter( property = "android.uiautomator.screenshotsPathOnDevice" )
248 private String uiautomatorScreenshotsPathOnDevice;
249
250 @PullParameter( required = false, defaultValue = "/sdcard/uiautomator-screenshots/" )
251 private String parsedScreenshotsPathOnDevice;
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 @Parameter( property = "android.uiautomator.propertiesKeyPrefix" )
269 private String uiautomatorPropertiesKeyPrefix;
270
271 @PullParameter( required = false, defaultValueGetterMethod = "getPropertiesKeyPrefix" )
272 private String parsedPropertiesKeyPrefix;
273
274 @Override
275 public void execute() throws MojoExecutionException, MojoFailureException
276 {
277 ConfigHandler configHandler = new ConfigHandler( this, this.session, this.execution );
278 configHandler.parseConfiguration();
279
280 if ( isEnableIntegrationTest() )
281 {
282 playTests();
283 }
284 }
285
286
287
288
289
290
291 protected boolean isEnableIntegrationTest()
292 {
293 return !parsedSkip && !mavenTestSkip && !mavenSkipTests;
294 }
295
296
297
298
299
300
301 protected boolean isIgnoreTestFailures()
302 {
303 return mavenIgnoreTestFailure || mavenTestFailureIgnore;
304 }
305
306
307
308
309
310
311
312
313
314 protected void playTests() throws MojoExecutionException, MojoFailureException
315 {
316
317 getLog().debug( "Parsed values for Android UI UIAutomator invocation: " );
318 getLog().debug( "jarFile:" + parsedJarFile );
319 String testClassOrMethodString = buildSpaceSeparatedString( parsedTestClassOrMethods );
320 getLog().debug( "testClassOrMethod:" + testClassOrMethodString );
321 getLog().debug( "createReport:" + parsedCreateReport );
322
323 DeviceCallback instrumentationTestExecutor = new DeviceCallback()
324 {
325 @Override
326 public void doWithDevice( final IDevice device ) throws MojoExecutionException, MojoFailureException
327 {
328 String deviceLogLinePrefix = DeviceHelper.getDeviceLogLinePrefix( device );
329
330 UIAutomatorRemoteAndroidTestRunner automatorRemoteAndroidTestRunner
331 = new UIAutomatorRemoteAndroidTestRunner( parsedJarFile, device );
332
333 automatorRemoteAndroidTestRunner.setRunName( "ui uiautomator tests" );
334 automatorRemoteAndroidTestRunner.setDebug( uiautomatorDebug );
335 automatorRemoteAndroidTestRunner.setTestClassOrMethods( parsedTestClassOrMethods );
336 automatorRemoteAndroidTestRunner.setNoHup( parsedNoHup );
337 automatorRemoteAndroidTestRunner.setUserProperties( session.getUserProperties(),
338 parsedPropertiesKeyPrefix );
339
340 if ( parsedUseDump )
341 {
342 automatorRemoteAndroidTestRunner.setDumpFilePath( parsedDumpFilePath );
343 }
344
345 getLog().info( deviceLogLinePrefix + "Running ui uiautomator tests in" + parsedJarFile );
346 try
347 {
348 AndroidTestRunListener testRunListener = new AndroidTestRunListener( device, getLog(),
349 parsedCreateReport, parsedTakeScreenshotOnFailure, parsedScreenshotsPathOnDevice,
350 parsedReportSuffix, targetDirectory );
351 automatorRemoteAndroidTestRunner.run( testRunListener );
352 if ( testRunListener.hasFailuresOrErrors() && !isIgnoreTestFailures() )
353 {
354 throw new MojoFailureException( deviceLogLinePrefix + "Tests failed on device." );
355 }
356 if ( testRunListener.testRunFailed() )
357 {
358 throw new MojoFailureException( deviceLogLinePrefix + "Test run failed to complete: "
359 + testRunListener.getTestRunFailureCause() );
360 }
361 if ( testRunListener.threwException() && !isIgnoreTestFailures() )
362 {
363 throw new MojoFailureException( deviceLogLinePrefix + testRunListener.getExceptionMessages() );
364 }
365 }
366 catch ( TimeoutException e )
367 {
368 throw new MojoExecutionException( deviceLogLinePrefix + "timeout", e );
369 }
370 catch ( AdbCommandRejectedException e )
371 {
372 throw new MojoExecutionException( deviceLogLinePrefix + "adb command rejected", e );
373 }
374 catch ( ShellCommandUnresponsiveException e )
375 {
376 throw new MojoExecutionException( deviceLogLinePrefix + "shell command " + "unresponsive", e );
377 }
378 catch ( IOException e )
379 {
380 throw new MojoExecutionException( deviceLogLinePrefix + "IO problem", e );
381 }
382 }
383 };
384
385 instrumentationTestExecutor = new ScreenshotServiceWrapper( instrumentationTestExecutor, project, getLog() );
386
387 doWithDevices( instrumentationTestExecutor );
388 }
389
390 private String getJarFile()
391 {
392 if ( parsedJarFile == null )
393 {
394 File jarFilePath = new File( targetDirectory + File.separator
395 + finalName + ".jar" );
396 return jarFilePath.getName();
397 }
398 return parsedJarFile;
399 }
400
401 private String[] getTestClassOrMethods()
402 {
403
404 return parsedTestClassOrMethods;
405 }
406
407 private String getReportSuffix()
408 {
409 return parsedReportSuffix;
410 }
411
412 private String getPropertiesKeyPrefix()
413 {
414 return parsedPropertiesKeyPrefix;
415 }
416
417
418
419
420
421
422
423
424 protected static String buildSpaceSeparatedString( String[] lines )
425 {
426 if ( lines == null || lines.length == 0 )
427 {
428 return null;
429 }
430
431 return StringUtils.join( lines, " " );
432 }
433 }