Package tlib :: Package base :: Module AndroidHelper |
[hide private]
[frames] | no frames]

# Source Code for Module tlib.base.AndroidHelper

      1  # noinspection PyPackageRequirements
      2  import requests
      3  import time
      4  # noinspection PyPackageRequirements
      5  import pytest
      6  import re
      7  from _pytest import runner
      8  from tlib.base import TestHelper
      9  import logging
     10
     11  DEVICE_UNPLUGGED = "disconnected"    # Device is not connected
     12  DEVICE_OFFLINE = "offline"           # Device is connected but offline
     13  DEVICE_UNAUTHORIZED = "unauthorized" # Unauthorized
     14  DEVICE_ONLINE = "online"             # Device is connected and accessible
     15
     16 -def is_webdriver_running(tlib_logger, adb_logger, log=True):
     17      """
     18      Function to validate if webdriver is running and a connection can be established
     19
     20      @param tlib_logger: TLib logger
     21      @type tlib_logger: logging.logger
     22      @param adb_logger: ADB logger
     23      @type adb_logger: logging.logger
     24      @param log: When true, log debugging information
     25      @type log: bool
     26      """
     27      try:
     28          if log: tlib_logger.debug("Checking if Webdriver is running")
     29          response = requests.get("http://localhost:8080/wd/hub/status", timeout=10)
     30      except requests.ConnectionError as e:
     31          if log: adb_logger.debug("Connection to Webdriver failed:\n%s" % e)
     32          return False
     33
     34      return response.status_code == 200
     35
     36
     37 -def get_device_status(tlib_logger, adb_logger, serial_id):
     38      """
     39      Get status of a device using it's serial id\n
     40      Serial id can be either a ID (for devices connected to USB) or an IP and port (For devices connected via IP)
     41
     42      @param tlib_logger: TLib logger
     43      @type tlib_logger: logging.logger
     44      @param adb_logger: ADB logger
     45      @type adb_logger: logging.logger
     46      @param serial_id: Device's serial number
     47      @type serial_id: str
     48      """
     49
     50      out = TestHelper.run_command(adb_logger, ["adb", "devices"], fail_on_error=False)
     51      if re.search(serial_id, out[0]) is None:
     52          tlib_logger.debug("Device {serial_id} is not connected".format(serial_id=serial_id))
     53          return DEVICE_UNPLUGGED
     54      elif re.search("{serial_id}\s+offline".format(serial_id=serial_id), out[0]) is not None:
     55          tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
     56          return DEVICE_OFFLINE
     57      elif re.search("{serial_id}\s+unauthorized".format(serial_id=serial_id), out[0]) is not None:
     58          tlib_logger.debug("Device {serial_id} is offline".format(serial_id=serial_id))
     59          return DEVICE_UNAUTHORIZED
     60      elif re.search("{serial_id}\s+device".format(serial_id=serial_id), out[0]) is not None:
     61          tlib_logger.debug("Device {serial_id} is online".format(serial_id=serial_id))
     62          return DEVICE_ONLINE
     63      else:
     64          tlib_logger.error("Unknown device status\n%s" % out[0])
     65          pytest.fail("Unknown device status\n%s" % out[0])
     66
     67
     68 -def setup_ip_connection(tlib_logger, adb_logger, serial_id):
     69      """
     70      Connects to an android device via IP and waits for the connection to be established.
     71
     72      @param tlib_logger: TLib logger
     73      @type tlib_logger: logging.logger
     74      @param adb_logger: ADB logger
     75      @type adb_logger: logging.logger
     76      @param serial_id: Device's serial number
     77      @type serial_id: str
     78      """
     79      # Validate is device is already connected
     80      tlib_logger.debug("Setting up IP connection to device {serial_id}".format(serial_id=serial_id))
     81      status = get_device_status(tlib_logger, adb_logger, serial_id)
     82
     83      if status == DEVICE_ONLINE:
     84          tlib_logger.debug("Device is already online".format(serial_id=serial_id))
     85          return
     86
     87      # If device is offline or unauthorized, disconnect
     88      if status == DEVICE_OFFLINE:
     89          tlib_logger.warn("Device {serial_id} is offline, disconnecting and retrying".format(serial_id=serial_id))
     90          terminate_ip_connection(tlib_logger, adb_logger, serial_id)
     91      elif status == DEVICE_UNAUTHORIZED:
     92          terminate_ip_connection(tlib_logger, adb_logger, serial_id)
     93          tlib_logger.error("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
     94          pytest.fail("Device {serial_id} is not authorized, aborting".format(serial_id=serial_id))
     95      elif status == DEVICE_UNPLUGGED:
     96          tlib_logger.warn("Device {serial_id} is disconecting, resetting connection".format(serial_id=serial_id))
     97          terminate_ip_connection(tlib_logger, adb_logger, serial_id)
     98
     99      timeout = 0.5
    100
    101      #We wait up to 3 seconds
    102      for i in range(1, int(3 / timeout)):
    103          out = TestHelper.run_command(adb_logger, ["adb", "connect", serial_id])
    104          log_adb_output(adb_logger, out)
    105
    106          if get_device_status(tlib_logger, adb_logger, serial_id) == DEVICE_ONLINE:
    107              tlib_logger.debug("Connected to device")
    108              return
    109          else:
    110              tlib_logger.debug("Not yet connected")
    111              time.sleep(timeout)
    112
    113      #If we're here, it means connection failed
    114      adb_logger.error(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".format(serial_id=serial_id, out=out))
    115      # noinspection PyUnresolvedReferences
    116      pytest.fail(r"Timeout while connecting to device {serial_id}\nADB output:\n{out}".format(serial_id=serial_id, out=out))
    117
    118
    119 -def terminate_ip_connection(tlib_logger, adb_logger, serial_id):
    120      """
    121      Disconnects from device
    122
    123      @param tlib_logger: TLib logger
    124      @type tlib_logger: logging.logger
    125      @param adb_logger: ADB logger
    126      @type adb_logger: logging.logger
    127      @param serial_id: Device's serial number
    128      @type serial_id: str
    129      """
    130      tlib_logger.debug("Disconnecting from device {serial_id}".format(serial_id=serial_id))
    131      out = TestHelper.run_command(adb_logger, ["adb", "disconnect", serial_id])
    132      log_adb_output(adb_logger, out)
    133
    134
    135 -def close_webdriver(tlib_logger, adb_logger, serial_id):
    136      """
    137      Stops Webdriver app o the device
    138
    139      @param tlib_logger: TLib logger
    140      @type tlib_logger: logging.logger
    141      @param adb_logger: ADB logger
    142      @type adb_logger: logging.logger
    143      @param serial_id: Device's serial number
    144      @type serial_id: str
    145      """
    146      tlib_logger.debug("Closing Webdriver on {serial_id}".format(serial_id=serial_id))
    147      if serial_id is None or serial_id == "":
    148          out = TestHelper.run_command(adb_logger,
    149                                ["adb", "shell", "am", "force-stop", "org.openqa.selenium.android.app"])
    150      else:
    151          out = TestHelper.run_command(adb_logger,
    152                                ["adb", "-s", serial_id, "shell", "am", "force-stop", "org.openqa.selenium.android.app"])
    153      log_adb_output(adb_logger, out)
    154
    155
    156 -def setup_port_forwarding(tlib_logger, adb_logger, serial_id):
    157      """
    158      Setup port forwarding between computer and device.
    159
    160      @param tlib_logger: TLib logger
    161      @type tlib_logger: logging.logger
    162      @param adb_logger: ADB logger
    163      @type adb_logger: logging.logger
    164      @param serial_id: Device's serial number
    165      @type serial_id: str
    166      """
    167      tlib_logger.info("Setting up port forwarding")
    168      if serial_id is None or serial_id == "":
    169          out = TestHelper.run_command(adb_logger, ["adb", "forward", "tcp:8080", "tcp:8080"])
    170      else:
    171          out = TestHelper.run_command(adb_logger, ["adb", "-s", serial_id, "forward", "tcp:8080", "tcp:8080"])
    172      log_adb_output(adb_logger, out)
    173
    174
    175 -def teardown_port_forwarding(tlib_logger, adb_logger):
    176      """
    177      Terminates all port forwarding connections
    178
    179      @param tlib_logger: TLib logger
    180      @type tlib_logger: logging.logger
    181      @param adb_logger: ADB logger
    182      @type adb_logger: logging.logger
    183      """
    184      tlib_logger.info("Tearing down port forwarding")
    185      out = TestHelper.run_command(adb_logger, ["adb", "forward", "--remove-all"])
    186      log_adb_output(adb_logger, out)
    187
    188
    189 -def stop_adb_server(tlib_logger, adb_logger):
    190      """
    191      Stops adb on the machine\n
    192      This can be required by TeamCity so some folders are not locked
    193
    194      @param tlib_logger: TLib logger
    195      @type tlib_logger: logging.logger
    196      @param adb_logger: ADB logger
    197      @type adb_logger: logging.logger
    198      """
    199      tlib_logger.info("Stopping ADB")
    200      out = TestHelper.run_command(adb_logger, ["adb", "kill-server"], fail_on_error=False)
    201      log_adb_output(adb_logger, out)
    202
    203
    204 -def start_webdriver(tlib_logger, adb_logger, serial_id):
    205      """
    206      Starts Webdriver app on  the device
    207
    208      @param tlib_logger: TLib logger
    209      @type tlib_logger: logging.logger
    210      @param adb_logger: ADB logger
    211      @type adb_logger: logging.logger
    212      @param serial_id: Device's serial number
    213      @type serial_id: str
    214      """
    215      tlib_logger.info("Starting webdriver on the device")
    216      if serial_id is None or serial_id == "":
    217          out = TestHelper.run_command(adb_logger, ["adb", "shell", "am", "start", "-a", "android.intent.action.MAIN",
    218                                         "-n", "org.openqa.selenium.android.app/.MainActivity", "-e", "debug", "true"])
    219      else:
    220          out = TestHelper.run_command(adb_logger,
    221                                ["adb", "-s", serial_id, "shell", "am", "start", "-a", "android.intent.action.MAIN",
    222                                 "-n", "org.openqa.selenium.android.app/.MainActivity",
    223                                 "-e", "debug", "true"])
    224      log_adb_output(adb_logger, out)
    225
    226
    227 -def wait_for_connection_to_webdriver(tlib_logger, adb_logger):
    228      """
    229      Waits up to 3 seconds for a connection to Webdriver
    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      """
    236      #Check connection to webdriver can be established. Retry 3 times
    237      tlib_logger.debug("Waiting for connection to Webdriver")
    238      timeout = 0.5
    239      for i in range(1, int(3 / timeout)):
    240          if is_webdriver_running(tlib_logger, adb_logger, False):
    241              tlib_logger.debug("Webdriver started successfully")
    242              break
    243          tlib_logger.debug("Can't connect to Webdriver, retrying in {timeout} seconds".format(timeout=timeout))
    244          time.sleep(timeout)
    245
    246      if not is_webdriver_running(tlib_logger, adb_logger, False):
    247          tlib_logger.error("Couldn't start Webdriver. Make sure it's installed and running\n"
    248                       "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator for more details")
    249          # noinspection PyUnresolvedReferences
    250          pytest.fail("Couldn't start Webdriver. Make sure it's installed and running\n"
    251                      "See https://code.google.com/p/selenium/wiki/AndroidDriver#Setup_the_Emulator for more details")
    252
    253
    254  # noinspection PyUnresolvedReferences
    255 -def setup_webdriver(tlib_logger, adb_logger, serial_id):
    256      """
    257      Connects to a device and starts webdriver
    258
    259      @param tlib_logger: TLib logger
    260      @type tlib_logger: logging.logger
    261      @param adb_logger: ADB logger
    262      @type adb_logger: logging.logger
    263      @param serial_id: Device's serial number
    264      @type serial_id: str
    265      """
    266      #Try to connect to Webdriver and exit if success
    267      if is_webdriver_running(tlib_logger, adb_logger, log=False):
    268          tlib_logger.debug("Already connected to device")
    269          return
    270
    271      tlib_logger.info("Connecting to Webdriver")
    272
    273      #Connect to device and setup port forwarding.
    274      if TestHelper.is_valid_ip(serial_id):
    275          setup_ip_connection(tlib_logger, adb_logger, serial_id)
    276
    277      setup_port_forwarding(tlib_logger, adb_logger, serial_id)
    278
    279      #Try again to connect to Webdriver and exit if success
    280      if is_webdriver_running(tlib_logger, adb_logger):
    281          tlib_logger.debug("Connected to Webdriver")
    282          return
    283
    284      # Webdriver not running, start it
    285      start_webdriver(tlib_logger, adb_logger, serial_id)
    286
    287      #Ensure we're connected
    288      wait_for_connection_to_webdriver(tlib_logger, adb_logger)
    289
    290      tlib_logger.info("Connection to Webdriver established")
    291
    292
    293  # noinspection PyUnresolvedReferences
    294 -def teardown_webdriver(tlib_logger, adb_logger, serial_id):
    295      """
    296      Closes webdriver and disconnects from device
    297
    298      @param tlib_logger: TLib logger
    299      @type tlib_logger: logging.logger
    300      @param adb_logger: ADB logger
    301      @type adb_logger: logging.logger
    302      @param serial_id: Device's serial number
    303      @type serial_id: str
    304      """
    305      #close selenium WebDriver
    306      tlib_logger.info("Disconnecting from Webdriver")
    307      close_webdriver(tlib_logger, adb_logger, serial_id)
    308
    309      # Terminates IP connection if an IP was given
    310      if TestHelper.is_valid_ip(serial_id):
    311          terminate_ip_connection(tlib_logger, adb_logger, serial_id)
    312
    313      #Stop adb service so it won't lock files required by TeamCity
    314      try:
    315          stop_adb_server(tlib_logger, adb_logger)
    316      except runner.Failed:
    317          #If ADB fails to stop, don't abort test
    318          adb_logger.warn("Error stopping ADB server")
    319
    320      tlib_logger.info("Disconnected from Webdriver")
    321
    322
    323 -def log_adb_output(logger, out):
    324      """
    325      Logs ADB output
    326
    327      @param logger: ADB logger
    328      @type logger: logging.logger
    329      """
    330      if out[0] is not None and out[0] != '':
    331          logger.debug("\n" + out[0])
    332
    333      if out[1] is not None and out[1] != '':
    334          logger.debug("\n" + out[1])
    335