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 import wmi
12
13 DEVICE_UNPLUGGED = "disconnected"
14 DEVICE_OFFLINE = "offline"
15 DEVICE_UNAUTHORIZED = "unauthorized"
16 DEVICE_ONLINE = "online"
17
18
20 """
21 Function to validate if webdriver is running and a connection can be established
22
23 @param tlib_logger: TLib logger
24 @type tlib_logger: logging.Logger
25 @param adb_logger: ADB logger
26 @type adb_logger: logging.Logger
27 @param log: When true, log debugging information
28 @type log: bool
29 """
30 try:
31 if log:
32 tlib_logger.debug("Checking if Webdriver is running")
33 response = requests.get("http://localhost:8080/wd/hub/status", timeout=10)
34 except requests.ConnectionError as e:
35 if log:
36 adb_logger.debug("Connection to Webdriver failed:\n%s" % e)
37 return False
38
39 return response.status_code == 200
40
41
43 """
44 Get status of a device using it's serial id\n
45 Serial id can be either a ID (for devices connected to USB) or an IP and port (For devices connected via IP)
46
47 @param tlib_logger: TLib logger
48 @type tlib_logger: logging.Logger
49 @param adb_logger: ADB logger
50 @type adb_logger: logging.Logger
51 @param serial_id: Device's serial number
52 @type serial_id: str
53 """
54
55 out = TestHelper.run_command(adb_logger, ["adb", "devices"], fail_on_error=False)
56 if re.search(serial_id, out[0]) is None:
57 tlib_logger.debug("Device {serial_id} is not connected".format(serial_id=serial_id))
58 return DEVICE_UNPLUGGED
59 elif re.search("{serial_id}\s+offline".format(serial_id=serial_id), out[0]) is not None:
60 tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
61 return DEVICE_OFFLINE
62 elif re.search("{serial_id}\s+unauthorized".format(serial_id=serial_id), out[0]) is not None:
63 tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
64 return DEVICE_UNAUTHORIZED
65 elif re.search("{serial_id}\s+device".format(serial_id=serial_id), out[0]) is not None:
66 tlib_logger.debug("Device {serial_id} is online".format(serial_id=serial_id))
67 return DEVICE_ONLINE
68 else:
69 tlib_logger.error("Unknown device status\n%s" % out[0])
70 raise RuntimeError("Unknown device status\n%s" % out[0])
71
72
74 """
75 Connects to an android device via IP and waits for the connection to be established.
76
77 @param tlib_logger: TLib logger
78 @type tlib_logger: logging.Logger
79 @param adb_logger: ADB logger
80 @type adb_logger: logging.Logger
81 @param serial_id: Device's serial number
82 @type serial_id: str
83 """
84
85 tlib_logger.debug("Setting up IP connection to device {serial_id}".format(serial_id=serial_id))
86 status = get_device_status(tlib_logger, adb_logger, serial_id)
87
88 if status == DEVICE_ONLINE:
89 tlib_logger.debug("Device is already online".format(serial_id=serial_id))
90 return
91
92
93 if status == DEVICE_OFFLINE:
94 tlib_logger.warn("Device {serial_id} is offline, disconnecting and retrying".format(serial_id=serial_id))
95 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
96 elif status == DEVICE_UNAUTHORIZED:
97 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
98 tlib_logger.error("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
99 raise RuntimeError("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
100 elif status == DEVICE_UNPLUGGED:
101 tlib_logger.warn("Device {serial_id} is disconecting, resetting connection".format(serial_id=serial_id))
102 terminate_ip_connection(tlib_logger, adb_logger, serial_id)
103
104 timeout = 0.5
105 out = None
106
107 for i in range(1, int(3 / timeout)):
108 out = TestHelper.run_command(adb_logger, ["adb", "connect", serial_id])
109 log_adb_output(adb_logger, out)
110
111 if get_device_status(tlib_logger, adb_logger, serial_id) == DEVICE_ONLINE:
112 tlib_logger.debug("Connected to device")
113 return
114 else:
115 tlib_logger.debug("Not yet connected")
116 time.sleep(timeout)
117
118
119 adb_logger.error(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".
120 format(serial_id=serial_id, out=out))
121
122 raise RuntimeError(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".
123 format(serial_id=serial_id, out=out))
124
125
127 """
128 Disconnects from device
129
130 @param tlib_logger: TLib logger
131 @type tlib_logger: logging.Logger
132 @param adb_logger: ADB logger
133 @type adb_logger: logging.Logger
134 @param serial_id: Device's serial number
135 @type serial_id: str
136 """
137 tlib_logger.debug("Disconnecting from device {serial_id}".format(serial_id=serial_id))
138 out = TestHelper.run_command(adb_logger, ["adb", "disconnect", serial_id])
139 log_adb_output(adb_logger, out)
140
141
143 """
144 Stops Webdriver app o the device
145
146 @param tlib_logger: TLib logger
147 @type tlib_logger: logging.Logger
148 @param adb_logger: ADB logger
149 @type adb_logger: logging.Logger
150 @param serial_id: Device's serial number
151 @type serial_id: str
152 """
153 tlib_logger.debug("Closing Webdriver on {serial_id}".format(serial_id=serial_id))
154 if serial_id is None or serial_id == "":
155 out = TestHelper.run_command(adb_logger,
156 "adb shell am force-stop org.openqa.selenium.android.app", shell=True)
157 else:
158 out = TestHelper.run_command(adb_logger,
159 "adb -s %s shell am force-stop org.openqa.selenium.android.app" % serial_id,
160 shell=True)
161 log_adb_output(adb_logger, out)
162
163
165 """
166 Setup port forwarding between computer and device.
167
168 @param tlib_logger: TLib logger
169 @type tlib_logger: logging.Logger
170 @param adb_logger: ADB logger
171 @type adb_logger: logging.Logger
172 @param serial_id: Device's serial number
173 @type serial_id: str
174 """
175 tlib_logger.info("Setting up port forwarding")
176 if serial_id is None or serial_id == "":
177 out = TestHelper.run_command(adb_logger, "adb forward tcp:8080 tcp:8080", shell=True)
178 else:
179 out = TestHelper.run_command(adb_logger, "adb -s %s forward tcp:8080 tcp:8080" % serial_id, shell=True)
180 log_adb_output(adb_logger, out)
181
182
184 """
185 Terminates all port forwarding connections
186
187 @param tlib_logger: TLib logger
188 @type tlib_logger: logging.Logger
189 @param adb_logger: ADB logger
190 @type adb_logger: logging.Logger
191 """
192 tlib_logger.info("Tearing down port forwarding")
193 out = TestHelper.run_command(adb_logger, "adb forward --remove-all", shell=True)
194 log_adb_output(adb_logger, out)
195
196
198 """
199 Stops adb on the machine\n
200 This can be required by TeamCity so some folders are not locked
201
202 @param tlib_logger: TLib logger
203 @type tlib_logger: logging.Logger
204 @param adb_logger: ADB logger
205 @type adb_logger: logging.Logger
206 """
207 tlib_logger.info("Starting ADB")
208 out = TestHelper.run_command(adb_logger, "adb start-server", fail_on_error=False)
209 log_adb_output(adb_logger, out)
210
211
213 """
214 Stops adb on the machine\n
215 This can be required by TeamCity so some folders are not locked
216
217 @param tlib_logger: TLib logger
218 @type tlib_logger: logging.Logger
219 @param adb_logger: ADB logger
220 @type adb_logger: logging.Logger
221 """
222 tlib_logger.info("Stopping ADB")
223 out = TestHelper.run_command(adb_logger, "adb kill-server", fail_on_error=False)
224 log_adb_output(adb_logger, out)
225
226
228 """
229 Starts Webdriver app on the device
230
231 @param tlib_logger: TLib logger
232 @type tlib_logger: logging.Logger
233 @param adb_logger: ADB logger
234 @type adb_logger: logging.Logger
235 @param serial_id: Device's serial number
236 @type serial_id: str
237 """
238 tlib_logger.info("Starting webdriver on the device")
239 if serial_id is None or serial_id == "":
240 out = TestHelper.run_command(adb_logger, "adb shell am start -a android.intent.action.MAIN -n "
241 "org.openqa.selenium.android.app/.MainActivity -e debug true", shell=True)
242 else:
243 out = TestHelper.run_command(adb_logger, "adb -s %s shell am start -a android.intent.action.MAIN "
244 "-n org.openqa.selenium.android.app/.MainActivity -e debug true" %
245 serial_id, shell=True)
246 log_adb_output(adb_logger, out)
247
248
250 """
251 Waits up to 3 seconds for a connection to Webdriver
252
253 @param tlib_logger: TLib logger
254 @type tlib_logger: logging.Logger
255 @param adb_logger: ADB logger
256 @type adb_logger: logging.Logger
257 """
258
259 tlib_logger.debug("Waiting for connection to Webdriver")
260 timeout = 0.5
261 for i in range(1, int(3 / timeout)):
262 if is_webdriver_running(tlib_logger, adb_logger, False):
263 tlib_logger.debug("Webdriver started successfully")
264 break
265 tlib_logger.debug("Can't connect to Webdriver, retrying in {timeout} seconds".format(timeout=timeout))
266 time.sleep(timeout)
267
268 if not is_webdriver_running(tlib_logger, adb_logger, False):
269 tlib_logger.error("Couldn't start Webdriver. Make sure it's installed and running\n"
270 "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator "
271 "for more details")
272
273 raise RuntimeError("Couldn't start Webdriver. Make sure it's installed and running\n"
274 "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator for more details")
275
276
277
279 """
280 Connects to a device and starts webdriver
281
282 @param tlib_logger: TLib logger
283 @type tlib_logger: logging.Logger
284 @param adb_logger: ADB logger
285 @type adb_logger: logging.Logger
286 @param serial_id: Device's serial number
287 @type serial_id: str
288 """
289
290 if is_webdriver_running(tlib_logger, adb_logger, log=False):
291 tlib_logger.debug("Already connected to device")
292 return
293
294 tlib_logger.info("Connecting to Webdriver")
295
296
297 if TestHelper.is_valid_ip(serial_id):
298 setup_ip_connection(tlib_logger, adb_logger, serial_id)
299
300 setup_port_forwarding(tlib_logger, adb_logger, serial_id)
301
302
303 if is_webdriver_running(tlib_logger, adb_logger):
304 tlib_logger.debug("Connected to Webdriver")
305 return
306
307
308 start_webdriver(tlib_logger, adb_logger, serial_id)
309
310
311 wait_for_connection_to_webdriver(tlib_logger, adb_logger)
312
313 tlib_logger.info("Connection to Webdriver established")
314
315
316
344
346 """
347 If the selenium server is running without a head, kill it
348 """
349
350 c = wmi.WMI()
351
352 for process in c.Win32_Process():
353 if "java" in process.name and "selendroid" in process.CommandLine:
354 tlib_logger.info("Trying to kill a Rogue Selenium Server before starting a new one")
355 res = os.system("taskkill /F /PID %s"%process.ProcessId)
356 if res != 0:
357 raise RuntimeError("Could not kill the Rogue Selenium Server")
358 break
359
360
361
390
391
393 """
394 Function to validate if selendroid/appium is running and a connection can be established
395
396 @param tlib_logger: TLib logger
397 @type tlib_logger: logging.Logger
398 @param adb_logger: ADB logger
399 @type adb_logger: logging.Logger
400 @param log: When true, log debugging information
401 @type log: bool
402 """
403 try:
404 tlib_logger.debug("Checking if Selendroid server is running")
405 response = requests.get("http://localhost:4444/wd/hub/status", timeout=10)
406 except requests.ConnectionError as e:
407 adb_logger.debug("Connection to Selendroid failed:\n%s" % e)
408 return False
409
410 return response.status_code == 200
411
412
414 """
415 @raise RuntimeError: Error connecting to selendroid or converting JSON payload
416 """
417 try:
418 response = requests.get("http://localhost:4444/wd/hub/status")
419 except Exception as e:
420 raise RuntimeError("Error connecting to selendroid\n%s" % e.message)
421
422 try:
423 response_json = response.json()
424 except Exception as e:
425 raise RuntimeError("Error converting response to json.\nResposne:%s\nError:\n%s" % (response, e.message))
426
427 for app in response_json['value']['supportedApps']:
428 if not app['appId'].startswith('io.selendroid.androiddriver'):
429 return app['appId']
430 return None
431
433 """
434 Logs ADB output
435
436 @param logger: ADB logger
437 @type logger: logging.Logger
438 """
439 if out[0] is not None and out[0] != '':
440 logger.debug("\n" + out[0])
441
442 if out[1] is not None and out[1] != '':
443 logger.debug("\n" + out[1])
444
463
464
466 """
467 Start appium server listening on port 4444 (default)
468
469 @param tlib_logger: TLib logger
470 @type tlib_logger: logging.Logger
471 @param adb_logger: Adb logger
472 @type adb_logger: logging.Logger
473 @param app_path: Location of the apk file
474 @type app_path: str
475 """
476 def appium_libs():
477 return os.path.join("lib", "server", "main.js")
478
479 def node_js():
480 return os.path.join("C:\\", "appium", "node.exe")
481
482 def working_dir():
483 return os.path.abspath(os.path.join("C:\\", "appium", "node_modules", "appium"))
484
485 def appium_command_line():
486 command_line = "{node_js} {appium} --address 127.0.0.1 --port 4444 --no-reset".format(node_js=node_js(),
487 appium=appium_libs())
488 return command_line
489
490
491 tlib_logger.info("Starting appium server")
492
493 if not os.path.isfile(node_js()):
494 tlib_logger.error("Appium is not installed on c:\appium")
495 raise RuntimeError("Appium is not installed on c:\appium\n"
496 "See https://wiki.ypg.com/pages/viewpage.action?pageId=163352061#Python+TLib-InstallTLib "
497 "for more information")
498
499 process = TestHelper.run_command(tlib_logger,
500 appium_command_line(),
501 shell=False,
502 cwd=working_dir(),
503 wait_until_complete=False)
504
505
506 trial_left = 20
507 while not is_selendroid_running(tlib_logger, adb_logger) and trial_left > 0:
508 time.sleep(0.5)
509 trial_left -= 1
510
511 if trial_left > 0:
512
513 return process
514 return None
515