1 import os
2 import requests
3 import time
4 import pytest
5 import re
6 from _pytest import runner
7 from tlib.base import TestHelper
8 import jsonpath_rw
9 import logging
10 from tlib.base.LogHelper import get_tlib_logger, get_adb_logger
11
12 DEVICE_UNPLUGGED = "disconnected"
13 DEVICE_OFFLINE = "offline"
14 DEVICE_UNAUTHORIZED = "unauthorized"
15 DEVICE_ONLINE = "online"
16
17
19 """
20 Function to validate if webdriver is running and a connection can be established
21
22 @param tlib_logger: TLib logger
23 @type tlib_logger: logging.Logger
24 @param adb_logger: ADB logger
25 @type adb_logger: logging.Logger
26 @param log: When true, log debugging information
27 @type log: bool
28 """
29 try:
30 if log:
31 tlib_logger.debug("Checking if Webdriver is running")
32 response = requests.get("http://localhost:8080/wd/hub/status", timeout=10)
33 except requests.ConnectionError as e:
34 if log:
35 adb_logger.debug("Connection to Webdriver failed:\n%s" % e)
36 return False
37
38 return response.status_code == 200
39
40
42 """
43 Get status of a device using it's serial id\n
44 Serial id can be either a ID (for devices connected to USB) or an IP and port (For devices connected via IP)
45
46 @param tlib_logger: TLib logger
47 @type tlib_logger: logging.Logger
48 @param adb_logger: ADB logger
49 @type adb_logger: logging.Logger
50 @param serial_id: Device's serial number
51 @type serial_id: str
52 """
53
54 out = TestHelper.run_command(adb_logger, ["adb", "devices"], fail_on_error=False)
55 if re.search(serial_id, out[0]) is None:
56 tlib_logger.debug("Device {serial_id} is not connected".format(serial_id=serial_id))
57 return DEVICE_UNPLUGGED
58 elif re.search("{serial_id}\s+offline".format(serial_id=serial_id), out[0]) is not None:
59 tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
60 return DEVICE_OFFLINE
61 elif re.search("{serial_id}\s+unauthorized".format(serial_id=serial_id), out[0]) is not None:
62 tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
63 return DEVICE_UNAUTHORIZED
64 elif re.search("{serial_id}\s+device".format(serial_id=serial_id), out[0]) is not None:
65 tlib_logger.debug("Device {serial_id} is online".format(serial_id=serial_id))
66 return DEVICE_ONLINE
67 else:
68 tlib_logger.error("Unknown device status\n%s" % out[0])
69 raise RuntimeError("Unknown device status\n%s" % out[0])
70
71
73 """
74 Connects to an android device via IP and waits for the connection to be established.
75
76 @param tlib_logger: TLib logger
77 @type tlib_logger: logging.Logger
78 @param adb_logger: ADB logger
79 @type adb_logger: logging.Logger
80 @param serial_id: Device's serial number
81 @type serial_id: str
82 """
83
84 tlib_logger.debug("Setting up IP connection to device {serial_id}".format(serial_id=serial_id))
85 status = get_device_status(tlib_logger, adb_logger, serial_id)
86
87 if status == DEVICE_ONLINE:
88 tlib_logger.debug("Device is already online".format(serial_id=serial_id))
89 return
90
91
92 if status == DEVICE_OFFLINE:
93 tlib_logger.warn("Device {serial_id} is offline, disconnecting and retrying".format(serial_id=serial_id))
94 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
95 elif status == DEVICE_UNAUTHORIZED:
96 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
97 tlib_logger.error("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
98 raise RuntimeError("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
99 elif status == DEVICE_UNPLUGGED:
100 tlib_logger.warn("Device {serial_id} is disconecting, resetting connection".format(serial_id=serial_id))
101 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
102
103 timeout = 0.5
104 out = None
105
106 for i in range(1, int(3 / timeout)):
107 out = TestHelper.run_command(adb_logger, ["adb", "connect", serial_id])
108 log_adb_output(adb_logger, out)
109
110 if get_device_status(tlib_logger, adb_logger, serial_id) == DEVICE_ONLINE:
111 tlib_logger.debug("Connected to device")
112 return
113 else:
114 tlib_logger.debug("Not yet connected")
115 time.sleep(timeout)
116
117
118 adb_logger.error(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".
119 format(serial_id=serial_id, out=out))
120
121 raise RuntimeError(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".
122 format(serial_id=serial_id, out=out))
123
124
126 """
127 Disconnects from device
128
129 @param tlib_logger: TLib logger
130 @type tlib_logger: logging.Logger
131 @param adb_logger: ADB logger
132 @type adb_logger: logging.Logger
133 @param serial_id: Device's serial number
134 @type serial_id: str
135 """
136 tlib_logger.debug("Disconnecting from device {serial_id}".format(serial_id=serial_id))
137 out = TestHelper.run_command(adb_logger, ["adb", "disconnect", serial_id])
138 log_adb_output(adb_logger, out)
139
140
142 """
143 Stops Webdriver app o the device
144
145 @param tlib_logger: TLib logger
146 @type tlib_logger: logging.Logger
147 @param adb_logger: ADB logger
148 @type adb_logger: logging.Logger
149 @param serial_id: Device's serial number
150 @type serial_id: str
151 """
152 tlib_logger.debug("Closing Webdriver on {serial_id}".format(serial_id=serial_id))
153 if serial_id is None or serial_id == "":
154 out = TestHelper.run_command(adb_logger,
155 "adb shell am force-stop org.openqa.selenium.android.app", shell=True)
156 else:
157 out = TestHelper.run_command(adb_logger,
158 "adb -s %s shell am force-stop org.openqa.selenium.android.app" % serial_id,
159 shell=True)
160 log_adb_output(adb_logger, out)
161
162
164 """
165 Setup port forwarding between computer and device.
166
167 @param tlib_logger: TLib logger
168 @type tlib_logger: logging.Logger
169 @param adb_logger: ADB logger
170 @type adb_logger: logging.Logger
171 @param serial_id: Device's serial number
172 @type serial_id: str
173 """
174 tlib_logger.info("Setting up port forwarding")
175 if serial_id is None or serial_id == "":
176 out = TestHelper.run_command(adb_logger, "adb forward tcp:8080 tcp:8080", shell=True)
177 else:
178 out = TestHelper.run_command(adb_logger, "adb -s %s forward tcp:8080 tcp:8080" % serial_id, shell=True)
179 log_adb_output(adb_logger, out)
180
181
183 """
184 Terminates all port forwarding connections
185
186 @param tlib_logger: TLib logger
187 @type tlib_logger: logging.Logger
188 @param adb_logger: ADB logger
189 @type adb_logger: logging.Logger
190 """
191 tlib_logger.info("Tearing down port forwarding")
192 out = TestHelper.run_command(adb_logger, "adb forward --remove-all", shell=True)
193 log_adb_output(adb_logger, out)
194
195
197 """
198 Stops adb on the machine\n
199 This can be required by TeamCity so some folders are not locked
200
201 @param tlib_logger: TLib logger
202 @type tlib_logger: logging.Logger
203 @param adb_logger: ADB logger
204 @type adb_logger: logging.Logger
205 """
206 tlib_logger.info("Starting ADB")
207 out = TestHelper.run_command(adb_logger, "adb start-server", fail_on_error=False)
208 log_adb_output(adb_logger, out)
209
210
212 """
213 Stops adb on the machine\n
214 This can be required by TeamCity so some folders are not locked
215
216 @param tlib_logger: TLib logger
217 @type tlib_logger: logging.Logger
218 @param adb_logger: ADB logger
219 @type adb_logger: logging.Logger
220 """
221 tlib_logger.info("Stopping ADB")
222 out = TestHelper.run_command(adb_logger, "adb kill-server", fail_on_error=False)
223 log_adb_output(adb_logger, out)
224
225
227 """
228 Starts Webdriver app on the device
229
230 @param tlib_logger: TLib logger
231 @type tlib_logger: logging.Logger
232 @param adb_logger: ADB logger
233 @type adb_logger: logging.Logger
234 @param serial_id: Device's serial number
235 @type serial_id: str
236 """
237 tlib_logger.info("Starting webdriver on the device")
238 if serial_id is None or serial_id == "":
239 out = TestHelper.run_command(adb_logger, "adb shell am start -a android.intent.action.MAIN -n "
240 "org.openqa.selenium.android.app/.MainActivity -e debug true", shell=True)
241 else:
242 out = TestHelper.run_command(adb_logger, "adb -s %s shell am start -a android.intent.action.MAIN "
243 "-n org.openqa.selenium.android.app/.MainActivity -e debug true" %
244 serial_id, shell=True)
245 log_adb_output(adb_logger, out)
246
247
249 """
250 Waits up to 3 seconds for a connection to Webdriver
251
252 @param tlib_logger: TLib logger
253 @type tlib_logger: logging.Logger
254 @param adb_logger: ADB logger
255 @type adb_logger: logging.Logger
256 """
257
258 tlib_logger.debug("Waiting for connection to Webdriver")
259 timeout = 0.5
260 for i in range(1, int(3 / timeout)):
261 if is_webdriver_running(tlib_logger, adb_logger, False):
262 tlib_logger.debug("Webdriver started successfully")
263 break
264 tlib_logger.debug("Can't connect to Webdriver, retrying in {timeout} seconds".format(timeout=timeout))
265 time.sleep(timeout)
266
267 if not is_webdriver_running(tlib_logger, adb_logger, False):
268 tlib_logger.error("Couldn't start Webdriver. Make sure it's installed and running\n"
269 "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator "
270 "for more details")
271
272 raise RuntimeError("Couldn't start Webdriver. Make sure it's installed and running\n"
273 "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator for more details")
274
275
276
278 """
279 Connects to a device and starts webdriver
280
281 @param tlib_logger: TLib logger
282 @type tlib_logger: logging.Logger
283 @param adb_logger: ADB logger
284 @type adb_logger: logging.Logger
285 @param serial_id: Device's serial number
286 @type serial_id: str
287 """
288
289 if is_webdriver_running(tlib_logger, adb_logger, log=False):
290 tlib_logger.debug("Already connected to device")
291 return
292
293 tlib_logger.info("Connecting to Webdriver")
294
295
296 if TestHelper.is_valid_ip(serial_id):
297 setup_ip_connection(tlib_logger, adb_logger, serial_id)
298
299 setup_port_forwarding(tlib_logger, adb_logger, serial_id)
300
301
302 if is_webdriver_running(tlib_logger, adb_logger):
303 tlib_logger.debug("Connected to Webdriver")
304 return
305
306
307 start_webdriver(tlib_logger, adb_logger, serial_id)
308
309
310 wait_for_connection_to_webdriver(tlib_logger, adb_logger)
311
312 tlib_logger.info("Connection to Webdriver established")
313
314
315
317 """
318 Closes webdriver and disconnects from device
319
320 @param tlib_logger: TLib logger
321 @type tlib_logger: logging.Logger
322 @param adb_logger: ADB logger
323 @type adb_logger: logging.Logger
324 @param serial_id: Device's serial number
325 @type serial_id: str
326 """
327
328 tlib_logger.info("Disconnecting from Webdriver")
329 close_webdriver(tlib_logger, adb_logger, serial_id)
330
331
332 if TestHelper.is_valid_ip(serial_id):
333 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
334
335
336 try:
337 stop_adb_server(tlib_logger, adb_logger)
338 except runner.Failed:
339
340 adb_logger.warn("Error stopping ADB server")
341
342 tlib_logger.info("Disconnected from Webdriver")
343
344
345
347 """
348 Start selendroid server and point to apk file
349
350 @param tlib_logger: TLib logger
351 @type tlib_logger: logging.Logger
352 @param adb_logger: Adb logger
353 @type adb_logger: logging.Logger
354 @param app_path: Location of the apk file
355 @type app_path: str
356 """
357 tlib_logger.info("Starting selendroid server")
358 stop_adb_server(tlib_logger, adb_logger)
359 start_adb_server(tlib_logger, adb_logger)
360 process = TestHelper.run_command(tlib_logger,
361 'java -jar "%s" -aut "%s"' % (TestHelper.selendroid_server_jar(), app_path),
362 shell=False,
363 wait_until_complete=False)
364
365 trial_left = 20
366 while not is_selendroid_running(tlib_logger, adb_logger) and trial_left > 0:
367 time.sleep(0.5)
368 trial_left -= 1
369 if trial_left > 0:
370 return process
371 return None
372
373
375 """
376 Function to validate if selendroid/appium is running and a connection can be established
377
378 @param tlib_logger: TLib logger
379 @type tlib_logger: logging.Logger
380 @param adb_logger: ADB logger
381 @type adb_logger: logging.Logger
382 @param log: When true, log debugging information
383 @type log: bool
384 """
385 try:
386 tlib_logger.debug("Checking if Selendroid server is running")
387 response = requests.get("http://localhost:4444/wd/hub/status", timeout=10)
388 except requests.ConnectionError as e:
389 adb_logger.debug("Connection to Selendroid failed:\n%s" % e)
390 return False
391
392 return response.status_code == 200
393
394
396 """
397 @raise RuntimeError: Error connecting to selendroid or converting JSON payload
398 """
399 try:
400 response = requests.get("http://localhost:4444/wd/hub/status")
401 except Exception as e:
402 raise RuntimeError("Error connecting to selendroid\n%s" % e.message)
403
404 try:
405 response_json = response.json()
406 except Exception as e:
407 raise RuntimeError("Error converting response to json.\nResposne:%s\nError:\n%s" % (response, e.message))
408
409 for app in response_json['value']['supportedApps']:
410 if not app['appId'].startswith('io.selendroid.androiddriver'):
411 return app['appId']
412 return None
413
415 """
416 Logs ADB output
417
418 @param logger: ADB logger
419 @type logger: logging.Logger
420 """
421 if out[0] is not None and out[0] != '':
422 logger.debug("\n" + out[0])
423
424 if out[1] is not None and out[1] != '':
425 logger.debug("\n" + out[1])
426
428 """
429 Stops adb on the machine\n
430 This can be required by TeamCity so some folders are not locked
431
432 @param tlib_logger: TLib logger
433 @type tlib_logger: logging.Logger
434 @param adb_logger: ADB logger
435 @type adb_logger: logging.Logger
436 """
437 tlib_logger = get_tlib_logger()
438 adb_logger = get_adb_logger()
439
440 start_adb_server(tlib_logger, adb_logger)
441 tlib_logger.info("Starting ADB")
442 out = TestHelper.run_command(adb_logger, "adb shell getprop ro.build.version.release", fail_on_error=False)
443 log_adb_output(adb_logger, out)
444 return out
445
446
448 """
449 Start appium server listening on port 4444 (default)
450
451 @param tlib_logger: TLib logger
452 @type tlib_logger: logging.Logger
453 @param adb_logger: Adb logger
454 @type adb_logger: logging.Logger
455 @param app_path: Location of the apk file
456 @type app_path: str
457 """
458 def appium_libs():
459 return os.path.join("lib", "server", "main.js")
460
461 def node_js():
462 return os.path.join("C:\\", "appium", "node.exe")
463
464 def working_dir():
465 return os.path.abspath(os.path.join("C:\\", "appium", "node_modules", "appium"))
466
467 def appium_command_line():
468 command_line = "{node_js} {appium} --address 127.0.0.1 --port 4444 --no-reset".format(node_js=node_js(),
469 appium=appium_libs())
470 return command_line
471
472
473 tlib_logger.info("Starting appium server")
474
475 if not os.path.isfile(node_js()):
476 tlib_logger.error("Appium is not installed on c:\appium")
477 raise RuntimeError("Appium is not installed on c:\appium\n"
478 "See https://wiki.ypg.com/pages/viewpage.action?pageId=163352061#Python+TLib-InstallTLib "
479 "for more information")
480
481 process = TestHelper.run_command(tlib_logger,
482 appium_command_line(),
483 shell=False,
484 cwd=working_dir(),
485 wait_until_complete=False)
486
487
488 trial_left = 20
489 while not is_selendroid_running(tlib_logger, adb_logger) and trial_left > 0:
490 time.sleep(0.5)
491 trial_left -= 1
492
493 if trial_left > 0:
494
495 return process
496 return None
497