def run_firefox_for_android(build_obj, params): """ Launch Firefox for Android on the connected device. Optional 'params' allow parameters to be passed to Firefox. """ adb_path = _find_sdk_exe(build_obj.substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) try: # # Construct an adb command similar to: # # $ adb shell am start -a android.activity.MAIN \ # -n org.mozilla.fennec_$USER \ # -d <url param> \ # --es args "<params>" # app = "%s/org.mozilla.gecko.BrowserApp" % build_obj.substs['ANDROID_PACKAGE_NAME'] cmd = ['am', 'start', '-a', 'android.activity.MAIN', '-n', app] if params: for p in params: if urlparse.urlparse(p).scheme != "": cmd.extend(['-d', p]) params.remove(p) break if params: cmd.extend(['--es', 'args', '"%s"' % ' '.join(params)]) _log_debug(cmd) output = dm.shellCheckOutput(cmd, timeout=10) _log_info(output) except DMError: _log_warning("unable to launch Firefox for Android") return 1 return 0
def run_firefox_for_android(build_obj, params): """ Launch Firefox for Android on the connected device. Optional 'params' allow parameters to be passed to Firefox. """ adb_path = _find_sdk_exe(build_obj.substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) try: # # Construct an adb command similar to: # # adb shell am start -a android.activity.MAIN -n org.mozilla.fennec_$USER -d <url param> --es args "<params>" # app = "%s/.App" % build_obj.substs['ANDROID_PACKAGE_NAME'] cmd = ['am', 'start', '-a', 'android.activity.MAIN', '-n', app] if params: for p in params: if urlparse.urlparse(p).scheme != "": cmd.extend(['-d', p]) params.remove(p) break if params: cmd.extend(['--es', 'args', '"%s"' % ' '.join(params)]) _log_debug(cmd) output = dm.shellCheckOutput(cmd, timeout=10) _log_info(output) except DMError: _log_warning("unable to launch Firefox for Android") return 1 return 0
def remoteInit(self): if (self.remoteInitialized != None): return self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" self.profiles = self.getProfiles() # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because # that calls "rm" on every single entry which takes a lot of additional time. print "Purging possible cache leftover directories..." self.dm.runCmd([ 'shell', 'rm', '-r', self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*" ]).communicate() self.remoteInitialized = True
def _get_device_platform(substs): # PIE executables are required when SDK level >= 21 - important for gdbserver adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) sdk_level = None try: cmd = ['getprop', 'ro.build.version.sdk'] _log_debug(cmd) output = dm.shellCheckOutput(cmd, timeout=10) if output: sdk_level = int(output) except: _log_warning("unable to determine Android sdk level") pie = '' if sdk_level and sdk_level >= 21: pie = '-pie' if substs['TARGET_CPU'].startswith('arm'): return 'arm%s' % pie if sdk_level and sdk_level >= 21: _log_warning( "PIE gdbserver is not yet available for x86: you may not be able to debug on this platform" ) return 'x86'
def setUp(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join( self.tempRemoteDir, os.path.basename(self.tempLocalFile))
def reset(self, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Now try to get the old profile(s) self.profiles = self.getProfiles() for profile in self.profiles: self.dm.removeDir(self.profileBase + "/" + profile) self.dm.removeFile(self.profileBase + "/profiles.ini") # Start Fennec, so a new profile is created self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) again self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile( prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully resetted profile."
def __init__(self, avd_type='4.3', verbose=False, substs=None, device_serial=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1, deviceSerial=device_serial) self.dm.default_timeout = 10 _log_debug("Emulator created with type %s" % self.avd_type)
def remoteInit(self): if (self.remoteInitialized != None): return self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" self.profiles = self.getProfiles() # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because # that calls "rm" on every single entry which takes a lot of additional time. print "Purging possible cache leftover directories..." self.dm.runCmd(['shell', 'rm', '-r', self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*"]).communicate() self.remoteInitialized = True
def check_marionette_exists(adb="adb"): dm = DeviceManagerADB(adbPath=adb) if dm.dirExists(INSTALL_DIR): return True else: dm.forward("tcp:2828", "tcp:2828") try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', 2828)) data = sock.recv(16) sock.close() if 'root' in data: return True except socket.error: return False return False
def __init__(self, adb="adb", serial=None): self.test_results = {} self.test_results_file = None self.m = None self.gaia_apps = None self.screenshot_path = None self.logcat_path = None self.app_name = None self.attempt = None self.num_apps = None self.device = None self.serial = serial self.port = None self.run_log = logging.getLogger('marketplace-test') if self.serial: self.dm = DeviceManagerADB(adbPath=adb, deviceSerial=serial) else: self.dm = DeviceManagerADB(adbPath=adb)
def setUp(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join(self.tempRemoteDir, os.path.basename(self.tempLocalFile))
def _get_device_platform(substs): # PIE executables are required when SDK level >= 21 - important for gdbserver adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) sdk_level = None try: cmd = ['getprop', 'ro.build.version.sdk'] _log_debug(cmd) output = dm.shellCheckOutput(cmd, timeout=10) if output: sdk_level = int(output) except: _log_warning("unable to determine Android sdk level") pie = '' if sdk_level and sdk_level >= 21: pie = '-pie' if substs['TARGET_CPU'].startswith('arm'): return 'arm%s' % pie return 'x86%s' % pie
def _get_device_platform(substs): # PIE executables are required when SDK level >= 21 - important for gdbserver adb_path = _find_sdk_exe(substs, "adb", False) if not adb_path: adb_path = "adb" dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) sdk_level = None try: cmd = ["getprop", "ro.build.version.sdk"] _log_debug(cmd) output = dm.shellCheckOutput(cmd, timeout=10) if output: sdk_level = int(output) except: _log_warning("unable to determine Android sdk level") pie = "" if sdk_level and sdk_level >= 21: pie = "-pie" if substs["TARGET_CPU"].startswith("arm"): return "arm%s" % pie return "x86%s" % pie
class DeviceManagerADBTestCase(unittest.TestCase): tempLocalDir = "tempDir" tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt") tempRemoteDir = None tempRemoteFile = None def setUp(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join( self.tempRemoteDir, os.path.basename(self.tempLocalFile)) def tearDown(self): os.remove(self.tempLocalFile) os.rmdir(self.tempLocalDir) if self.dm.dirExists(self.tempRemoteDir): self.dm.removeDir(self.tempRemoteDir)
class DeviceManagerADBTestCase(unittest.TestCase): tempLocalDir = "tempDir" tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt") tempRemoteDir = None tempRemoteFile = None def setUp(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join(self.tempRemoteDir, os.path.basename(self.tempLocalFile)) def tearDown(self): os.remove(self.tempLocalFile) os.rmdir(self.tempLocalDir) if self.dm.dirExists(self.tempRemoteDir): self.dm.removeDir(self.tempRemoteDir)
def __init__(self, avd_type="4.3", verbose=False, substs=None): self.emulator_log = None self.emulator_path = "emulator" self.verbose = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = self._find_sdk_exe("adb", False) if not adb_path: adb_path = "adb" self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) self.dm.default_timeout = 10 self._log_debug("Emulator created with type %s" % self.avd_type)
def reset(self, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Now try to get the old profile(s) self.profiles = self.getProfiles() for profile in self.profiles: self.dm.removeDir(self.profileBase + "/" + profile) self.dm.removeFile(self.profileBase + "/profiles.ini") # Start Fennec, so a new profile is created self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) again self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile(prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully resetted profile."
def __init__(self, avd_type="4.3", verbose=False, substs=None, device_serial=None): global verbose_logging self.emulator_log = None self.emulator_path = "emulator" verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = _find_sdk_exe(substs, "adb", False) if not adb_path: adb_path = "adb" self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1, deviceSerial=device_serial) self.dm.default_timeout = 10 _log_debug("Emulator created with type %s" % self.avd_type)
def __init__(self, avd_type='4.3', verbose=False, substs=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = self._find_sdk_exe('adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) self.dm.default_timeout = 10 _log_debug("Emulator created with type %s" % self.avd_type)
def verify_device(self, adb_path, device): """ Check that the specified device is available and rooted. """ try: dm = DeviceManagerADB(adbPath=adb_path, retryLimit=1, deviceSerial=device) if dm._haveSu or dm._haveRootShell: return True except: self.build_obj.log(logging.WARN, "autophone", {}, "Unable to verify root on device.") if self.verbose: self.build_obj.log(logging.ERROR, "autophone", {}, str(sys.exc_info()[0])) return False
def __init__(self, avd_type='4.3', verbose=False, substs=None, device_serial=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] self.gpu = True self.restarted = False adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1, deviceSerial=device_serial) self.dm.default_timeout = 10 _log_debug("Running on %s" % platform.platform()) _log_debug("Emulator created with type %s" % self.avd_type)
class DeviceManagerADBTestCase(unittest.TestCase): tempLocalDir = "tempDir" tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt") tempRemoteDir = None tempRemoteFile = None tempRemoteSystemFile = None def setUp(self): self.assertTrue(find_mount_permissions(self.dm, "/system"), "ro") self.assertTrue(os.path.exists(self.tempLocalDir)) self.assertTrue(os.path.exists(self.tempLocalFile)) if self.dm.fileExists(self.tempRemoteFile): self.dm.removeFile(self.tempRemoteFile) self.assertFalse(self.dm.fileExists(self.tempRemoteFile)) if self.dm.fileExists(self.tempRemoteSystemFile): self.dm.removeFile(self.tempRemoteSystemFile) self.assertTrue(self.dm.dirExists(self.tempRemoteDir)) @classmethod def setUpClass(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join( self.tempRemoteDir, os.path.basename(self.tempLocalFile)) self.tempRemoteSystemFile = \ os.path.join("/system", os.path.basename(self.tempLocalFile)) @classmethod def tearDownClass(self): os.remove(self.tempLocalFile) os.rmdir(self.tempLocalDir) if self.dm.dirExists(self.tempRemoteDir): # self.tempRemoteFile will get deleted with it self.dm.removeDir(self.tempRemoteDir) if self.dm.fileExists(self.tempRemoteSystemFile): self.dm.removeFile(self.tempRemoteSystemFile)
class DeviceManagerADBTestCase(unittest.TestCase): tempLocalDir = "tempDir" tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt") tempRemoteDir = None tempRemoteFile = None tempRemoteSystemFile = None def setUp(self): self.assertTrue(find_mount_permissions(self.dm, "/system"), "ro") self.assertTrue(os.path.exists(self.tempLocalDir)) self.assertTrue(os.path.exists(self.tempLocalFile)) if self.dm.fileExists(self.tempRemoteFile): self.dm.removeFile(self.tempRemoteFile) self.assertFalse(self.dm.fileExists(self.tempRemoteFile)) if self.dm.fileExists(self.tempRemoteSystemFile): self.dm.removeFile(self.tempRemoteSystemFile) self.assertTrue(self.dm.dirExists(self.tempRemoteDir)) @classmethod def setUpClass(self): self.dm = DeviceManagerADB() if not os.path.exists(self.tempLocalDir): os.mkdir(self.tempLocalDir) if not os.path.exists(self.tempLocalFile): # Create empty file open(self.tempLocalFile, 'w').close() self.tempRemoteDir = self.dm.getTempDir() self.tempRemoteFile = os.path.join(self.tempRemoteDir, os.path.basename(self.tempLocalFile)) self.tempRemoteSystemFile = \ os.path.join("/system", os.path.basename(self.tempLocalFile)) @classmethod def tearDownClass(self): os.remove(self.tempLocalFile) os.rmdir(self.tempLocalDir) if self.dm.dirExists(self.tempRemoteDir): # self.tempRemoteFile will get deleted with it self.dm.removeDir(self.tempRemoteDir) if self.dm.fileExists(self.tempRemoteSystemFile): self.dm.removeFile(self.tempRemoteSystemFile)
def test_run_adb_as_root_parameter(self): dm = DeviceManagerADB() self.assertTrue(dm.processInfo("adbd")[2] != "root") dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") def test_after_reboot_adb_runs_as_root(self): dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") dm.reboot(wait=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") def tearDown(self): dm = DeviceManagerADB() dm.reboot() if __name__ == "__main__": dm = DeviceManagerADB() if not dm.devices(): print "There are no connected adb devices" sys.exit(1) else: if not (int(dm._runCmd(["shell", "getprop", "ro.secure"]).output[0]) and int(dm._runCmd(["shell", "getprop", "ro.debuggable"]).output[0])): print "This test case is meant for devices with devices that start " \ "adbd as non-root and allows for adbd to be restarted as root." sys.exit(1) unittest.main()
def setUp(self): dm = DeviceManagerADB() dm.reboot(wait=True)
def test_run_adb_as_root_parameter(self): dm = DeviceManagerADB() self.assertTrue(dm.processInfo("adbd")[2] != "root") dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root")
class AndroidEmulator(object): """ Support running the Android emulator with an AVD from Mozilla test automation. Example usage: emulator = AndroidEmulator() if not emulator.is_running() and emulator.is_available(): if not emulator.check_avd(): warn("this may take a while...") emulator.update_avd() emulator.start() emulator.wait_for_start() emulator.wait() """ def __init__(self, avd_type='4.3', verbose=False, substs=None, device_serial=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] self.gpu = True self.restarted = False adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1, deviceSerial=device_serial) self.dm.default_timeout = 10 _log_debug("Running on %s" % platform.platform()) _log_debug("Emulator created with type %s" % self.avd_type) def __del__(self): if self.emulator_log: self.emulator_log.close() def is_running(self): """ Returns True if the Android emulator is running. """ for proc in psutil.process_iter(): name = proc.name() # On some platforms, "emulator" may start an emulator with # process name "emulator64-arm" or similar. if name and name.startswith('emulator'): return True return False def is_available(self): """ Returns True if an emulator executable is found. """ found = False emulator_path = _find_sdk_exe(self.substs, 'emulator', True) if emulator_path: self.emulator_path = emulator_path found = True return found def check_avd(self, force=False): """ Determine if the AVD is already installed locally. (This is usually used to determine if update_avd() is likely to require a download; it is a convenient way of determining whether a 'this may take a while' warning is warranted.) Returns True if the AVD is installed. """ avd = os.path.join( EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') if force and os.path.exists(avd): shutil.rmtree(avd) if os.path.exists(avd): _log_debug("AVD found at %s" % avd) return True return False def update_avd(self, force=False): """ If required, update the AVD via tooltool. If the AVD directory is not found, or "force" is requested, download the tooltool manifest associated with the AVD and then invoke tooltool.py on the manifest. tooltool.py will download the required archive (unless already present in the local tooltool cache) and install the AVD. """ avd = os.path.join( EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') ini_file = os.path.join( EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.ini') if force and os.path.exists(avd): shutil.rmtree(avd) if not os.path.exists(avd): if os.path.exists(ini_file): os.remove(ini_file) path = self.avd_info.tooltool_manifest _get_tooltool_manifest(self.substs, path, EMULATOR_HOME_DIR, 'releng.manifest') _tooltool_fetch() self._update_avd_paths() def start(self): """ Launch the emulator. """ if os.path.exists(EMULATOR_AUTH_FILE): os.remove(EMULATOR_AUTH_FILE) _log_debug("deleted %s" % EMULATOR_AUTH_FILE) # create an empty auth file to disable emulator authentication auth_file = open(EMULATOR_AUTH_FILE, 'w') auth_file.close() def outputHandler(line): self.emulator_log.write("<%s>\n" % line) if "Invalid value for -gpu" in line or "Invalid GPU mode" in line: self.gpu = False env = os.environ env['ANDROID_AVD_HOME'] = os.path.join(EMULATOR_HOME_DIR, "avd") command = [self.emulator_path, "-avd", self.avd_info.name, "-port", "5554"] if self.gpu: command += ['-gpu', 'swiftshader'] if self.avd_info.extra_args: # -enable-kvm option is not valid on OSX if _get_host_platform() == 'macosx64' and '-enable-kvm' in self.avd_info.extra_args: self.avd_info.extra_args.remove('-enable-kvm') command += self.avd_info.extra_args log_path = os.path.join(EMULATOR_HOME_DIR, 'emulator.log') self.emulator_log = open(log_path, 'w') _log_debug("Starting the emulator with this command: %s" % ' '.join(command)) _log_debug("Emulator output will be written to '%s'" % log_path) self.proc = ProcessHandler( command, storeOutput=False, processOutputLine=outputHandler, env=env) self.proc.run() _log_debug("Emulator started with pid %d" % int(self.proc.proc.pid)) def wait_for_start(self): """ Verify that the emulator is running, the emulator device is visible to adb, and Android has booted. """ if not self.proc: _log_warning("Emulator not started!") return False if self.check_completed(): return False _log_debug("Waiting for device status...") while(('emulator-5554', 'device') not in self.dm.devices()): time.sleep(10) if self.check_completed(): return False _log_debug("Device status verified.") _log_debug("Checking that Android has booted...") complete = False while(not complete): output = '' try: output = self.dm.shellCheckOutput( ['getprop', 'sys.boot_completed'], timeout=5) except DMError: # adb not yet responding...keep trying pass if output.strip() == '1': complete = True else: time.sleep(10) if self.check_completed(): return False _log_debug("Android boot status verified.") if not self._verify_emulator(): return False if self.avd_info.x86: _log_info("Running the x86 emulator; be sure to install an x86 APK!") else: _log_info("Running the arm emulator; be sure to install an arm APK!") return True def check_completed(self): if self.proc.proc.poll() is not None: if not self.gpu and not self.restarted: _log_warning("Emulator failed to start. Your emulator may be out of date.") _log_warning("Trying to restart the emulator without -gpu argument.") self.restarted = True self.start() return False _log_warning("Emulator has already completed!") log_path = os.path.join(EMULATOR_HOME_DIR, 'emulator.log') _log_warning("See log at %s and/or use --verbose for more information." % log_path) return True return False def wait(self): """ Wait for the emulator to close. If interrupted, close the emulator. """ try: self.proc.wait() except: if self.proc.poll() is None: self.cleanup() return self.proc.poll() def cleanup(self): """ Close the emulator. """ self.proc.kill(signal.SIGTERM) def get_avd_description(self): """ Return the human-friendly description of this AVD. """ return self.avd_info.description def _update_avd_paths(self): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") ini_file = os.path.join(avd_path, "test-1.ini") ini_file_new = os.path.join(avd_path, self.avd_info.name + ".ini") os.rename(ini_file, ini_file_new) avd_dir = os.path.join(avd_path, "test-1.avd") avd_dir_new = os.path.join(avd_path, self.avd_info.name + ".avd") os.rename(avd_dir, avd_dir_new) self._replace_ini_contents(ini_file_new) def _replace_ini_contents(self, path): with open(path, "r") as f: lines = f.readlines() with open(path, "w") as f: for line in lines: if line.startswith('path='): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") f.write('path=%s/%s.avd\n' % (avd_path, self.avd_info.name)) elif line.startswith('path.rel='): f.write('path.rel=avd/%s.avd\n' % self.avd_info.name) else: f.write(line) def _telnet_cmd(self, telnet, command): _log_debug(">>> " + command) telnet.write('%s\n' % command) result = telnet.read_until('OK', 10) _log_debug("<<< " + result) return result def _verify_emulator(self): telnet_ok = False tn = None while(not telnet_ok): try: tn = telnetlib.Telnet('localhost', 5554, 10) if tn is not None: tn.read_until('OK', 10) self._telnet_cmd(tn, 'avd status') self._telnet_cmd(tn, 'redir list') self._telnet_cmd(tn, 'network status') tn.write('quit\n') tn.read_all() telnet_ok = True else: _log_warning("Unable to connect to port 5554") except: _log_warning("Trying again after unexpected exception") finally: if tn is not None: tn.close() if not telnet_ok: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False return telnet_ok def _get_avd_type(self, requested): if requested in AVD_DICT.keys(): return requested if self.substs: if not self.substs['TARGET_CPU'].startswith('arm'): return 'x86' return '4.3'
def test_after_reboot_adb_runs_as_root(self): dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") dm.reboot(wait=True) self.assertTrue(dm.processInfo("adbd")[2] == "root")
def run_remote_reftests(parser, options, args): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator auto.setEmulator(True) if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logdir: kwargs['logdir'] = options.logdir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath if options.emulator_res: kwargs['emulator_res'] = options.emulator_res if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host, port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) if options.adb_path: kwargs['adb_path'] = options.adb_path marionette = Marionette(**kwargs) auto.marionette = marionette if options.emulator: dm = marionette.emulator.dm else: # create the DeviceManager kwargs = { 'adbPath': options.adb_path, 'deviceRoot': options.remoteTestRoot } if options.deviceIP: kwargs.update({ 'host': options.deviceIP, 'port': options.devicePort }) dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) options = parser.verifyRemoteOptions(options, auto) if (options == None): print "ERROR: Invalid options specified, use --help for a list of valid options" sys.exit(1) # TODO fix exception if not options.ignoreWindowSize: parts = dm.getInfo('screen')['screen'][0].split() width = int(parts[0].split(':')[1]) height = int(parts[1].split(':')[1]) if (width < 1366 or height < 1050): print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % ( width, height) return 1 auto.setProduct("b2g") auto.test_script = os.path.join(here, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) options = parser.verifyCommonOptions(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent) auto.setRemoteLog(options.remoteLogFile) auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) # Hack in a symbolic link for jsreftest os.system( "ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot manifest = args[0] if os.path.exists(os.path.join(here, args[0])): manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0]) elif os.path.exists(args[0]): manifestPath = os.path.abspath(args[0]).split(here)[1].strip('/') manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath) else: print "ERROR: Could not find test manifest '%s'" % manifest return 1 # Start the webserver retVal = 1 try: retVal = reftest.startWebServer(options) if retVal: return retVal procName = options.app.split('/')[-1] if (dm.processExist(procName)): dm.killProcess(procName) cmdlineArgs = ["-reftest", manifest] if getattr(options, 'bootstrap', False): cmdlineArgs = [] retVal = reftest.runTests(manifest, options, cmdlineArgs) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() reftest.stopWebServer(options) try: reftest.cleanup(None) except: pass return 1 reftest.stopWebServer(options) return retVal
def __init__(self, **kwargs): DeviceManagerADB.__init__(self, **kwargs) B2GMixin.__init__(self, **kwargs)
root=True) output = str(out.getvalue()).rstrip().splitlines() out.close() self.assertEquals(output, ['Mozilla', '/']) def test_port_forwarding(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("", 0)) port = s.getsockname()[1] s.close() # If successful then no exception is raised self.dm.forward("tcp:%s" % port, "tcp:2828") def test_port_forwarding_error(self): self.assertRaises(DMError, self.dm.forward, "", "") if __name__ == '__main__': dm = DeviceManagerADB() if not dm.devices(): print "There are no connected adb devices" sys.exit(1) if find_mount_permissions(dm, "/system") == "rw": print "We've found out that /system is mounted as 'rw'. This is because the command " \ "'adb remount' has been run before running this test case. Please reboot the device " \ "and try again." sys.exit(1) unittest.main()
class ADBFuzz: def __init__(self, cfgFile): self.config = ADBFuzzConfig(cfgFile) self.HTTPProcess = None self.logProcesses = [] self.logThreads = [] self.remoteInitialized = None self.triager = Triager(self.config) # Seed RNG with localtime random.seed() def deploy(self, packageFile, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) self.dm.updateApp(packageFile) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Start Fennec, so a profile is created if this is the first install self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile( prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully deployed package." def reset(self, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Now try to get the old profile(s) self.profiles = self.getProfiles() for profile in self.profiles: self.dm.removeDir(self.profileBase + "/" + profile) self.dm.removeFile(self.profileBase + "/profiles.ini") # Start Fennec, so a new profile is created self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) again self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile( prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully resetted profile." def remoteInit(self): if (self.remoteInitialized != None): return self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" self.profiles = self.getProfiles() # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because # that calls "rm" on every single entry which takes a lot of additional time. print "Purging possible cache leftover directories..." self.dm.runCmd([ 'shell', 'rm', '-r', self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*" ]).communicate() self.remoteInitialized = True def signal_handler(self, signal, frame): self.cleanupProcesses() sys.exit(0) def cleanupProcesses(self): self.stopFennec() if (self.HTTPProcess != None): try: self.HTTPProcess.terminate() except: pass if (self.logProcesses != None): try: self.stopLoggers() except: pass def loopFuzz(self, maxIterations=None): try: iterations = 0 while (maxIterations == None or maxIterations >= iterations): self.runFuzzer() iterations += 1 except: self.cleanupProcesses() raise def runFuzzer(self): self.remoteInit() # Ensure Fennec isn't running if self.isFennecRunning(): self.stopFennec() # Clean all existing minidumps if not self.clearMinidumps(): raise Exception("Failed to clean existing minidumps") # Start our HTTP server for serving the fuzzer code self.HTTPProcess = self.startHTTPServer() # Start all loggers self.startLoggers() # Start Fennec self.startFennec() # Even though the program is already running, we should grant it # some extra time to load the fuzzer source and start running, # so it isn't directly diagnosed as hanging time.sleep(10) logSize = 0 hangDetected = False forceRestart = False while (self.isFennecRunning() and not self.checkLoggingThreads()): time.sleep(self.config.runTimeout) if not os.path.exists(self.logFile): raise Exception( "Logfile not present. If you are using websockets, this could indicate a network problem." ) # Poor man's hang detection. Yes, this is a bad # idea, just for the sake of proof-of-concept newLogSize = os.path.getsize(self.logFile) if (logSize == newLogSize): hangDetected = True break else: logSize = newLogSize if newLogSize > self.config.maxLogSize: forceRestart = True break if hangDetected or forceRestart: self.stopFennec() self.stopLoggers() print "Hang detected or running too long, restarting..." else: try: # Fennec died or a logger found something checkCrashDump = True crashUUID = None minidump = None # If Fennec is still running, stop it now if self.isFennecRunning(): checkCrashDump = False self.stopFennec() # Terminate our logging processes first self.stopLoggers() if checkCrashDump: dumps = self.getMinidumps() if (len(dumps) > 1): raise Exception("Multiple dumps detected!") if (len(dumps) < 1): raise Exception("No crash dump detected!") if not self.fetchMinidump(dumps[0]): raise Exception("Failed to fetch minidump with UUID " + dumps[0]) crashUUID = dumps[0] # Copy logfiles shutil.copy2(self.syslogFile, dumps[0] + ".syslog") shutil.copy2(self.logFile, dumps[0] + ".log") minidump = Minidump(dumps[0] + ".dmp", self.config.libDir) else: # We need to generate an arbitrary ID here crashUUID = str(uuid.uuid4()) # Copy logfiles shutil.copy2(self.syslogFile, crashUUID + ".syslog") shutil.copy2(self.logFile, crashUUID + ".log") print "Crash detected. Reproduction logfile stored at: " + crashUUID + ".log" if checkCrashDump: crashTrace = minidump.getCrashTrace() crashType = minidump.getCrashType() print "Crash type: " + crashType print "Crash backtrace:" print "" print crashTrace else: print "Crash type: Abnormal behavior (e.g. Assertion violation)" self.triager.process(crashUUID, minidump, crashUUID + ".syslog", crashUUID + ".log") except Exception, e: print "Error during crash processing: " print traceback.format_exc() self.HTTPProcess.terminate() return
def configure_devices(self): """ Ensure devices.ini is set up. """ keep_going = True device_ini = os.path.join(self.config['base-dir'], 'devices.ini') if os.path.exists(device_ini): response = raw_input( "Use existing device configuration at %s? (Y/n) " % device_ini).strip() if 'n' not in response.lower(): self.build_obj.log( logging.INFO, "autophone", {}, "Using device configuration at %s" % device_ini) return keep_going keep_going = False self.build_obj.log( logging.INFO, "autophone", {}, "You must configure at least one Android device " "before running autophone.") response = raw_input("Configure devices now? (Y/n) ").strip() if response.lower().startswith('y') or response == '': response = raw_input( "Connect your rooted Android test device(s) with usb and press Enter " ) adb_path = 'adb' try: if os.path.exists(self.build_obj.substs["ADB"]): adb_path = self.build_obj.substs["ADB"] except: if self.verbose: self.build_obj.log(logging.ERROR, "autophone", {}, str(sys.exc_info()[0])) # No build environment? try: adb_path = which.which('adb') except which.WhichError: adb_path = raw_input( "adb not found. Enter path to adb: ").strip() if self.verbose: print("Using adb at %s" % adb_path) dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) device_index = 1 try: with open(os.path.join(self.config['base-dir'], 'devices.ini'), 'w') as f: for device in dm.devices(): serial = device[0] if self.verify_device(adb_path, serial): f.write("[device-%d]\nserialno=%s\n" % (device_index, serial)) device_index += 1 self.build_obj.log( logging.INFO, "autophone", {}, "Added '%s' to device configuration." % serial) keep_going = True else: self.build_obj.log( logging.WARNING, "autophone", {}, "Device '%s' is not rooted - skipping" % serial) except: self.build_obj.log( logging.ERROR, "autophone", {}, "Failed to get list of connected Android devices.") if self.verbose: self.build_obj.log(logging.ERROR, "autophone", {}, str(sys.exc_info()[0])) keep_going = False if device_index <= 1: self.build_obj.log( logging.ERROR, "autophone", {}, "No devices configured! (Can you see your rooted test device(s)" " in 'adb devices'?") keep_going = False if keep_going: self.config['devices-configured'] = True return keep_going
def test_run_adb_as_root_parameter(self): dm = DeviceManagerADB() self.assertTrue(dm.processInfo("adbd")[2] != "root") dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") def test_after_reboot_adb_runs_as_root(self): dm = DeviceManagerADB(runAdbAsRoot=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") dm.reboot(wait=True) self.assertTrue(dm.processInfo("adbd")[2] == "root") def tearDown(self): dm = DeviceManagerADB() dm.reboot() if __name__ == "__main__": dm = DeviceManagerADB() if not dm.devices(): print("There are no connected adb devices") sys.exit(1) else: if not (int(dm._runCmd(["shell", "getprop", "ro.secure"]).output[0]) and int(dm._runCmd(["shell", "getprop", "ro.debuggable"]).output[0])): print("This test case is meant for devices with devices that start " "adbd as non-root and allows for adbd to be restarted as root.") sys.exit(1) unittest.main()
def run_remote_mochitests(automation, parser, options): # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator automation.setEmulator(True) if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logcat_dir: kwargs['logcat_dir'] = options.logcat_dir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath # needless to say sdcard is only valid if using an emulator if options.sdcard: kwargs['sdcard'] = options.sdcard if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host, port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) marionette = Marionette.getMarionetteOrExit(**kwargs) automation.marionette = marionette # create the DeviceManager kwargs = {'adbPath': options.adbPath, 'deviceRoot': options.remoteTestRoot} if options.deviceIP: kwargs.update({'host': options.deviceIP, 'port': options.devicePort}) dm = DeviceManagerADB(**kwargs) automation.setDeviceManager(dm) options = parser.verifyRemoteOptions(options, automation) if (options == None): print "ERROR: Invalid options specified, use --help for a list of valid options" sys.exit(1) automation.setProduct("b2g") mochitest = B2GDeviceMochitest(automation, dm, options) options = parser.verifyOptions(options, mochitest) if (options == None): sys.exit(1) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent) automation.setRemoteLog(options.remoteLogFile) automation.setServerInfo(options.webServer, options.httpPort, options.sslPort) retVal = 1 try: mochitest.cleanup(None, options) retVal = mochitest.runTests(options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() mochitest.stopWebServer(options) mochitest.stopWebSocketServer(options) try: mochitest.cleanup(None, options) except: pass retVal = 1 sys.exit(retVal)
class ADBFuzz: def __init__(self, cfgFile): self.config = ADBFuzzConfig(cfgFile) self.HTTPProcess = None self.logProcesses = [] self.logThreads = [] self.remoteInitialized = None self.triager = Triager(self.config) # Seed RNG with localtime random.seed() def deploy(self, packageFile, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) self.dm.updateApp(packageFile) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Start Fennec, so a profile is created if this is the first install self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile(prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully deployed package." def reset(self, prefFile): self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) # Standard init stuff self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" # Ensure no Fennec instance is running self.stopFennec() # Now try to get the old profile(s) self.profiles = self.getProfiles() for profile in self.profiles: self.dm.removeDir(self.profileBase + "/" + profile) self.dm.removeFile(self.profileBase + "/profiles.ini") # Start Fennec, so a new profile is created self.startFennec(blank=True) # Grant some time to create profile time.sleep(self.config.runTimeout * 2) # Stop Fennec again self.stopFennec() # Now try to get the profile(s) again self.profiles = self.getProfiles() if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Push prefs.js to profile self.dm.pushFile(prefFile, self.profileBase + "/" + self.defaultProfile + "/prefs.js") # Try to install addon if requested by configuration if self.config.addon != None: self.ensureExtensionInstalled(self.config.addon) print "Successfully resetted profile." def remoteInit(self): if (self.remoteInitialized != None): return self.dm = DeviceManagerADB(self.config.remoteAddr, 5555) self.appName = self.dm.packageName self.appRoot = self.dm.getAppRoot(self.appName) self.profileBase = self.appRoot + "/files/mozilla" self.profiles = self.getProfiles() # Install a signal handler that shuts down our external programs on SIGINT signal.signal(signal.SIGINT, self.signal_handler) if (len(self.profiles) == 0): print "Failed to detect any valid profile, aborting..." return 1 self.defaultProfile = self.profiles[0] if (len(self.profiles) > 1): print "Multiple profiles detected, using the first: " + self.defaultProfile # Workaround for bug 754575. Avoid using DeviceManagerADB's "removeDir" because # that calls "rm" on every single entry which takes a lot of additional time. print "Purging possible cache leftover directories..." self.dm.runCmd(['shell', 'rm', '-r', self.profileBase + "/" + self.defaultProfile + "/Cache.Trash*"]).communicate() self.remoteInitialized = True def signal_handler(self, signal, frame): self.cleanupProcesses() sys.exit(0) def cleanupProcesses(self): self.stopFennec() if (self.HTTPProcess != None): try: self.HTTPProcess.terminate() except: pass if (self.logProcesses != None): try: self.stopLoggers() except: pass def loopFuzz(self, maxIterations=None): try: iterations = 0 while (maxIterations == None or maxIterations >= iterations): self.runFuzzer() iterations += 1 except: self.cleanupProcesses() raise def runFuzzer(self): self.remoteInit() # Ensure Fennec isn't running if self.isFennecRunning(): self.stopFennec() # Clean all existing minidumps if not self.clearMinidumps(): raise Exception("Failed to clean existing minidumps") # Start our HTTP server for serving the fuzzer code self.HTTPProcess = self.startHTTPServer() # Start all loggers self.startLoggers() # Start Fennec self.startFennec() # Even though the program is already running, we should grant it # some extra time to load the fuzzer source and start running, # so it isn't directly diagnosed as hanging time.sleep(10); logSize = 0 hangDetected = False forceRestart = False while(self.isFennecRunning() and not self.checkLoggingThreads()): time.sleep(self.config.runTimeout) if not os.path.exists(self.logFile): raise Exception("Logfile not present. If you are using websockets, this could indicate a network problem.") # Poor man's hang detection. Yes, this is a bad # idea, just for the sake of proof-of-concept newLogSize = os.path.getsize(self.logFile) if (logSize == newLogSize): hangDetected = True break else: logSize = newLogSize if newLogSize > self.config.maxLogSize: forceRestart = True break if hangDetected or forceRestart: self.stopFennec() self.stopLoggers() print "Hang detected or running too long, restarting..." else: try: # Fennec died or a logger found something checkCrashDump = True crashUUID = None minidump = None # If Fennec is still running, stop it now if self.isFennecRunning(): checkCrashDump = False self.stopFennec() # Terminate our logging processes first self.stopLoggers() if checkCrashDump: dumps = self.getMinidumps() if (len(dumps) > 1): raise Exception("Multiple dumps detected!") if (len(dumps) < 1): raise Exception("No crash dump detected!") if not self.fetchMinidump(dumps[0]): raise Exception("Failed to fetch minidump with UUID " + dumps[0]) crashUUID = dumps[0] # Copy logfiles shutil.copy2(self.syslogFile, dumps[0] + ".syslog") shutil.copy2(self.logFile, dumps[0] + ".log") minidump = Minidump(dumps[0] + ".dmp", self.config.libDir) else: # We need to generate an arbitrary ID here crashUUID = str(uuid.uuid4()) # Copy logfiles shutil.copy2(self.syslogFile, crashUUID + ".syslog") shutil.copy2(self.logFile, crashUUID + ".log") print "Crash detected. Reproduction logfile stored at: " + crashUUID + ".log" if checkCrashDump: crashTrace = minidump.getCrashTrace() crashType = minidump.getCrashType() print "Crash type: " + crashType print "Crash backtrace:" print "" print crashTrace else: print "Crash type: Abnormal behavior (e.g. Assertion violation)" self.triager.process(crashUUID, minidump, crashUUID + ".syslog", crashUUID + ".log") except Exception, e: print "Error during crash processing: " print traceback.format_exc() self.HTTPProcess.terminate() return
def test_remount(self): self.assertEquals(self.dm.remount(), 0) def test_list_devices(self): self.assertEquals(len(list(self.dm.devices())), 1) def test_shell(self): out = StringIO() self.dm.shell(["echo", "$COMPANY", ";", "pwd"], out, env={"COMPANY":"Mozilla"}, cwd="/", timeout=4, root=True) output = str(out.getvalue()).rstrip().splitlines() out.close() self.assertEquals(output, ['Mozilla', '/']) def test_reboot(self): # We are not running the reboot function because it takes too long #self.dm.reboot(wait=True) pass def test_port_forwarding(self): # I don't really know how to test this properly self.assertEquals(self.dm.forward("tcp:2828", "tcp:2828"), 0) if __name__ == '__main__': dm = DeviceManagerADB() if not dm.devices(): print "There are no connected adb devices" sys.exit(1) unittest.main()
class AndroidEmulator(object): """ Support running the Android emulator with an AVD from Mozilla test automation. Example usage: emulator = AndroidEmulator() if not emulator.is_running() and emulator.is_available(): if not emulator.check_avd(): warn("this may take a while...") emulator.update_avd() emulator.start() emulator.wait_for_start() emulator.wait() """ def __init__(self, avd_type='4.3', verbose=False, substs=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = self._find_sdk_exe('adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) self.dm.default_timeout = 10 _log_debug("Emulator created with type %s" % self.avd_type) def __del__(self): if self.emulator_log: self.emulator_log.close() def is_running(self): """ Returns True if the Android emulator is running. """ for proc in psutil.process_iter(): name = proc.name() # On some platforms, "emulator" may start an emulator with # process name "emulator64-arm" or similar. if name and name.startswith('emulator'): return True return False def is_available(self): """ Returns True if an emulator executable is found. """ found = False emulator_path = self._find_sdk_exe('emulator', True) if emulator_path: self.emulator_path = emulator_path found = True return found def check_avd(self, force=False): """ Determine if the AVD is already installed locally. (This is usually used to determine if update_avd() is likely to require a download; it is a convenient way of determining whether a 'this may take a while' warning is warranted.) Returns True if the AVD is installed. """ avd = os.path.join( EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') if force and os.path.exists(avd): shutil.rmtree(avd) if os.path.exists(avd): _log_debug("AVD found at %s" % avd) return True return False def update_avd(self, force=False): """ If required, update the AVD via tooltool. If the AVD directory is not found, or "force" is requested, download the tooltool manifest associated with the AVD and then invoke tooltool.py on the manifest. tooltool.py will download the required archive (unless already present in the local tooltool cache) and install the AVD. """ avd = os.path.join( EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') if force and os.path.exists(avd): shutil.rmtree(avd) if not os.path.exists(avd): _download_file(TOOLTOOL_URL, 'tooltool.py', EMULATOR_HOME_DIR) url = '%s/%s' % (TRY_URL, self.avd_info.tooltool_manifest) _download_file(url, 'releng.manifest', EMULATOR_HOME_DIR) _tooltool_fetch() self._update_avd_paths() def start(self): """ Launch the emulator. """ def outputHandler(line): self.emulator_log.write("<%s>\n" % line) env = os.environ env['ANDROID_AVD_HOME'] = os.path.join(EMULATOR_HOME_DIR, "avd") command = [self.emulator_path, "-avd", self.avd_info.name, "-port", "5554"] if self.avd_info.extra_args: command += self.avd_info.extra_args log_path = os.path.join(EMULATOR_HOME_DIR, 'emulator.log') self.emulator_log = open(log_path, 'w') _log_debug("Starting the emulator with this command: %s" % ' '.join(command)) _log_debug("Emulator output will be written to '%s'" % log_path) self.proc = ProcessHandler( command, storeOutput=False, processOutputLine=outputHandler, env=env) self.proc.run() _log_debug("Emulator started with pid %d" % int(self.proc.proc.pid)) def wait_for_start(self): """ Verify that the emulator is running, the emulator device is visible to adb, and Android has booted. """ if not self.proc: _log_warning("Emulator not started!") return False if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Waiting for device status...") while(('emulator-5554', 'device') not in self.dm.devices()): time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Device status verified.") _log_debug("Checking that Android has booted...") complete = False while(not complete): output = '' try: output = self.dm.shellCheckOutput( ['getprop', 'sys.boot_completed'], timeout=5) except DMError: # adb not yet responding...keep trying pass if output.strip() == '1': complete = True else: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Android boot status verified.") if not self._verify_emulator(): return False if self.avd_info.uses_sut: if not self._verify_sut(): return False return True def wait(self): """ Wait for the emulator to close. If interrupted, close the emulator. """ try: self.proc.wait() except: if self.proc.poll() is None: self.cleanup() return self.proc.poll() def cleanup(self): """ Close the emulator. """ self.proc.kill(signal.SIGTERM) def get_avd_description(self): """ Return the human-friendly description of this AVD. """ return self.avd_info.description def _update_avd_paths(self): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") ini_file = os.path.join(avd_path, "test-1.ini") ini_file_new = os.path.join(avd_path, self.avd_info.name + ".ini") os.rename(ini_file, ini_file_new) avd_dir = os.path.join(avd_path, "test-1.avd") avd_dir_new = os.path.join(avd_path, self.avd_info.name + ".avd") os.rename(avd_dir, avd_dir_new) self._replace_ini_contents(ini_file_new) def _replace_ini_contents(self, path): with open(path, "r") as f: lines = f.readlines() with open(path, "w") as f: for line in lines: if line.startswith('path='): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") f.write('path=%s/%s.avd\n' % (avd_path, self.avd_info.name)) elif line.startswith('path.rel='): f.write('path.rel=avd/%s.avd\n' % self.avd_info.name) else: f.write(line) def _telnet_cmd(self, telnet, command): _log_debug(">>> " + command) telnet.write('%s\n' % command) result = telnet.read_until('OK', 10) _log_debug("<<< " + result) return result def _verify_emulator(self): telnet_ok = False tn = None while(not telnet_ok): try: tn = telnetlib.Telnet('localhost', self.avd_info.port, 10) if tn is not None: res = tn.read_until('OK', 10) self._telnet_cmd(tn, 'avd status') if self.avd_info.uses_sut: cmd = 'redir add tcp:%s:%s' % \ (str(self.avd_info.sut_port), str(self.avd_info.sut_port)) self._telnet_cmd(tn, cmd) cmd = 'redir add tcp:%s:%s' % \ (str(self.avd_info.sut_port2), str(self.avd_info.sut_port2)) self._telnet_cmd(tn, cmd) self._telnet_cmd(tn, 'redir list') self._telnet_cmd(tn, 'network status') tn.write('quit\n') tn.read_all() telnet_ok = True else: _log_warning("Unable to connect to port %d" % port) except: _log_warning("Trying again after unexpected exception") finally: if tn is not None: tn.close() if not telnet_ok: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False return telnet_ok def _verify_sut(self): sut_ok = False while(not sut_ok): try: tn = telnetlib.Telnet('localhost', self.avd_info.sut_port, 10) if tn is not None: _log_debug( "Connected to port %d" % self.avd_info.sut_port) res = tn.read_until('$>', 10) if res.find('$>') == -1: _log_debug("Unexpected SUT response: %s" % res) else: _log_debug("SUT response: %s" % res) sut_ok = True tn.write('quit\n') tn.read_all() except: _log_debug("Caught exception while verifying sutagent") finally: if tn is not None: tn.close() if not sut_ok: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False return sut_ok def _get_avd_type(self, requested): if requested in AVD_DICT.keys(): return requested if self.substs: if not self.substs['TARGET_CPU'].startswith('arm'): return 'x86' if self.substs['MOZ_ANDROID_MIN_SDK_VERSION'] == '9': return '2.3' return '4.3' def _find_sdk_exe(self, exe, tools): if tools: subdir = 'tools' var = 'ANDROID_TOOLS' else: subdir = 'platform-tools' var = 'ANDROID_PLATFORM_TOOLS' found = False # Can exe be found in the Android SDK? try: android_sdk_root = os.environ['ANDROID_SDK_ROOT'] exe_path = os.path.join( android_sdk_root, subdir, exe) if os.path.exists(exe_path): found = True else: _log_debug( "Unable to find executable at %s" % exe_path) except KeyError: _log_debug("ANDROID_SDK_ROOT not set") if not found and self.substs: # Can exe be found in ANDROID_TOOLS/ANDROID_PLATFORM_TOOLS? try: exe_path = os.path.join( self.substs[var], exe) if os.path.exists(exe_path): found = True else: _log_debug( "Unable to find executable at %s" % exe_path) except KeyError: _log_debug("%s not set" % var) if not found: # Can exe be found in the default bootstrap location? mozbuild_path = os.environ.get('MOZBUILD_STATE_PATH', os.path.expanduser(os.path.join('~', '.mozbuild'))) exe_path = os.path.join( mozbuild_path, 'android-sdk-linux', subdir, exe) if os.path.exists(exe_path): found = True else: _log_debug( "Unable to find executable at %s" % exe_path) if not found: # Is exe on PATH? exe_path = find_executable(exe) if exe_path: found = True else: _log_debug("Unable to find executable on PATH") if found: _log_debug("%s found at %s" % (exe, exe_path)) else: exe_path = None return exe_path
def tearDown(self): dm = DeviceManagerADB() dm.reboot()
def run_remote_mochitests(parser, options): # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logcat_dir: kwargs['logcat_dir'] = options.logcat_dir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath # needless to say sdcard is only valid if using an emulator if options.sdcard: kwargs['sdcard'] = options.sdcard if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host, port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) marionette = Marionette.getMarionetteOrExit(**kwargs) if options.emulator: dm = marionette.emulator.dm else: # create the DeviceManager kwargs = {'adbPath': options.adbPath, 'deviceRoot': options.remoteTestRoot} if options.deviceIP: kwargs.update({'host': options.deviceIP, 'port': options.devicePort}) dm = DeviceManagerADB(**kwargs) options = parser.verifyRemoteOptions(options) if (options == None): print "ERROR: Invalid options specified, use --help for a list of valid options" sys.exit(1) mochitest = B2GDeviceMochitest(marionette, dm, options.profile_data_dir, options.xrePath, remote_test_root=options.remoteTestRoot, remote_log_file=options.remoteLogFile) options = parser.verifyOptions(options, mochitest) if (options == None): sys.exit(1) retVal = 1 try: mochitest.cleanup(None, options) retVal = mochitest.run_tests(options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() mochitest.stopWebServer(options) mochitest.stopWebSocketServer(options) try: mochitest.cleanup(None, options) except: pass retVal = 1 sys.exit(retVal)
def grant_runtime_permissions(build_obj, app): """ Grant required runtime permissions to the specified app (typically org.mozilla.fennec_$USER). """ adb_path = _find_sdk_exe(build_obj.substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) dm.default_timeout = 10 try: sdk_level = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk']) if sdk_level and int(sdk_level) >= 23: _log_info("Granting important runtime permissions to %s" % app) dm.shellCheckOutput([ 'pm', 'grant', app, 'android.permission.WRITE_EXTERNAL_STORAGE' ]) dm.shellCheckOutput([ 'pm', 'grant', app, 'android.permission.ACCESS_FINE_LOCATION' ]) dm.shellCheckOutput( ['pm', 'grant', app, 'android.permission.CAMERA']) dm.shellCheckOutput( ['pm', 'grant', app, 'android.permission.WRITE_CONTACTS']) except DMError: _log_warning("Unable to grant runtime permissions to %s" % app)
class AndroidEmulator(object): """ Support running the Android emulator with an AVD from Mozilla test automation. Example usage: emulator = AndroidEmulator() if not emulator.is_running() and emulator.is_available(): if not emulator.check_avd(): warn("this may take a while...") emulator.update_avd() emulator.start() emulator.wait_for_start() emulator.wait() """ def __init__(self, avd_type="4.3", verbose=False, substs=None): self.emulator_log = None self.emulator_path = "emulator" self.verbose = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = self._find_sdk_exe("adb", False) if not adb_path: adb_path = "adb" self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) self.dm.default_timeout = 10 self._log_debug("Emulator created with type %s" % self.avd_type) def __del__(self): if self.emulator_log: self.emulator_log.close() def is_running(self): """ Returns True if the Android emulator is running. """ for proc in psutil.process_iter(): name = proc.name() # On some platforms, "emulator" may start an emulator with # process name "emulator64-arm" or similar. if name and name.startswith("emulator"): return True return False def is_available(self): """ Returns True if an emulator executable is found. """ found = False emulator_path = self._find_sdk_exe("emulator", True) if emulator_path: self.emulator_path = emulator_path found = True return found def check_avd(self, force=False): """ Determine if the AVD is already installed locally. (This is usually used to determine if update_avd() is likely to require a download; it is a convenient way of determining whether a 'this may take a while' warning is warranted.) Returns True if the AVD is installed. """ avd = os.path.join(EMULATOR_HOME_DIR, "avd", self.avd_info.name + ".avd") if force and os.path.exists(avd): shutil.rmtree(avd) if os.path.exists(avd): self._log_debug("AVD found at %s" % avd) return True return False def update_avd(self, force=False): """ If required, update the AVD via tooltool. If the AVD directory is not found, or "force" is requested, download the tooltool manifest associated with the AVD and then invoke tooltool.py on the manifest. tooltool.py will download the required archive (unless already present in the local tooltool cache) and install the AVD. """ avd = os.path.join(EMULATOR_HOME_DIR, "avd", self.avd_info.name + ".avd") if force and os.path.exists(avd): shutil.rmtree(avd) if not os.path.exists(avd): self._fetch_tooltool() self._fetch_tooltool_manifest() self._tooltool_fetch() self._update_avd_paths() def start(self): """ Launch the emulator. """ def outputHandler(line): self.emulator_log.write("<%s>\n" % line) env = os.environ env["ANDROID_AVD_HOME"] = os.path.join(EMULATOR_HOME_DIR, "avd") command = [self.emulator_path, "-avd", self.avd_info.name, "-port", "5554"] if self.avd_info.extra_args: command += self.avd_info.extra_args log_path = os.path.join(EMULATOR_HOME_DIR, "emulator.log") self.emulator_log = open(log_path, "w") self._log_debug("Starting the emulator with this command: %s" % " ".join(command)) self._log_debug("Emulator output will be written to '%s'" % log_path) self.proc = ProcessHandler(command, storeOutput=False, processOutputLine=outputHandler, env=env) self.proc.run() self._log_debug("Emulator started with pid %d" % int(self.proc.proc.pid)) def wait_for_start(self): """ Verify that the emulator is running, the emulator device is visible to adb, and Android has booted. """ if not self.proc: self._log_warning("Emulator not started!") return False if self.proc.proc.poll() is not None: self._log_warning("Emulator has already completed!") return False self._log_debug("Waiting for device status...") while ("emulator-5554", "device") not in self.dm.devices(): time.sleep(10) if self.proc.proc.poll() is not None: self._log_warning("Emulator has already completed!") return False self._log_debug("Device status verified.") self._log_debug("Checking that Android has booted...") complete = False while not complete: output = "" try: output = self.dm.shellCheckOutput(["getprop", "sys.boot_completed"], timeout=5) except DMError: # adb not yet responding...keep trying pass if output.strip() == "1": complete = True else: time.sleep(10) if self.proc.proc.poll() is not None: self._log_warning("Emulator has already completed!") return False self._log_debug("Android boot status verified.") if not self._verify_emulator(): return False if self.avd_info.uses_sut: if not self._verify_sut(): return False return True def wait(self): """ Wait for the emulator to close. If interrupted, close the emulator. """ try: self.proc.wait() except: if self.proc.poll() is None: self.cleanup() return self.proc.poll() def cleanup(self): """ Close the emulator. """ self.proc.kill(signal.SIGTERM) def get_avd_description(self): """ Return the human-friendly description of this AVD. """ return self.avd_info.description def _log_debug(self, text): if self.verbose: print "DEBUG: %s" % text def _log_warning(self, text): print "WARNING: %s" % text def _fetch_tooltool(self): self._download_file(TOOLTOOL_URL, "tooltool.py", EMULATOR_HOME_DIR) def _fetch_tooltool_manifest(self): url = "https://hg.mozilla.org/%s/raw-file/%s/%s" % ("try", "default", self.avd_info.tooltool_manifest) self._download_file(url, "releng.manifest", EMULATOR_HOME_DIR) def _tooltool_fetch(self): def outputHandler(line): self._log_debug(line) command = ["python", "tooltool.py", "fetch", "-m", "releng.manifest"] proc = ProcessHandler(command, processOutputLine=outputHandler, storeOutput=False, cwd=EMULATOR_HOME_DIR) proc.run() try: proc.wait() except: if proc.poll() is None: proc.kill(signal.SIGTERM) def _update_avd_paths(self): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") ini_file = os.path.join(avd_path, "test-1.ini") ini_file_new = os.path.join(avd_path, self.avd_info.name + ".ini") os.rename(ini_file, ini_file_new) avd_dir = os.path.join(avd_path, "test-1.avd") avd_dir_new = os.path.join(avd_path, self.avd_info.name + ".avd") os.rename(avd_dir, avd_dir_new) self._replace_ini_contents(ini_file_new) def _download_file(self, url, filename, path): f = urllib2.urlopen(url) if not os.path.isdir(path): try: os.makedirs(path) except Exception, e: self._log_warning(str(e)) return False local_file = open(os.path.join(path, filename), "wb") local_file.write(f.read()) local_file.close() self._log_debug("Downloaded %s to %s/%s" % (url, path, filename)) return True
def grant_runtime_permissions(build_obj): """ Grant required runtime permissions to the specified app (typically org.mozilla.fennec_$USER). """ app = build_obj.substs['ANDROID_PACKAGE_NAME'] adb_path = _find_sdk_exe(build_obj.substs, 'adb', False) if not adb_path: adb_path = 'adb' dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) dm.default_timeout = 10 try: sdk_level = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk']) if sdk_level and int(sdk_level) >= 23: _log_info("Granting important runtime permissions to %s" % app) dm.shellCheckOutput(['pm', 'grant', app, 'android.permission.WRITE_EXTERNAL_STORAGE']) dm.shellCheckOutput(['pm', 'grant', app, 'android.permission.READ_EXTERNAL_STORAGE']) dm.shellCheckOutput(['pm', 'grant', app, 'android.permission.ACCESS_FINE_LOCATION']) dm.shellCheckOutput(['pm', 'grant', app, 'android.permission.CAMERA']) except DMError: _log_warning("Unable to grant runtime permissions to %s" % app)
def dm(self): if not self._dm: from mozdevice import DeviceManagerADB self._dm = DeviceManagerADB(adbPath=self.adb_path) return self._dm
def run_remote_reftests(parser, options): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator auto.setEmulator(True) if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logdir: kwargs['logdir'] = options.logdir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath if options.emulator_res: kwargs['emulator_res'] = options.emulator_res if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host,port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) if options.adb_path: kwargs['adb_path'] = options.adb_path marionette = Marionette(**kwargs) auto.marionette = marionette if options.emulator: dm = marionette.emulator.dm else: # create the DeviceManager kwargs = {'adbPath': options.adb_path, 'deviceRoot': options.remoteTestRoot} if options.deviceIP: kwargs.update({'host': options.deviceIP, 'port': options.devicePort}) dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) parser.validate_remote(options, auto) # TODO fix exception if not options.ignoreWindowSize: parts = dm.getInfo('screen')['screen'][0].split() width = int(parts[0].split(':')[1]) height = int(parts[1].split(':')[1]) if (width < 1366 or height < 1050): print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) return 1 auto.setProduct("b2g") auto.test_script = os.path.join(here, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) parser.validate(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent); auto.setRemoteLog(options.remoteLogFile) auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) # Hack in a symbolic link for jsreftest os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) # Start the webserver retVal = 1 try: retVal = reftest.startWebServer(options) if retVal: return retVal procName = options.app.split('/')[-1] if (dm.processExist(procName)): dm.killProcess(procName) retVal = reftest.runTests(options.tests, options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() reftest.stopWebServer(options) try: reftest.cleanup(None) except: pass return 1 reftest.stopWebServer(options) return retVal
def main(args=sys.argv[1:]): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) parser = B2GOptions(auto) options, args = parser.parse_args(args) # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator auto.setEmulator(True) if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logcat_dir: kwargs['logcat_dir'] = options.logcat_dir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath if options.emulator_res: kwargs['emulator_res'] = options.emulator_res if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host,port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) marionette = Marionette.getMarionetteOrExit(**kwargs) auto.marionette = marionette # create the DeviceManager kwargs = {'adbPath': options.adbPath, 'deviceRoot': options.remoteTestRoot} if options.deviceIP: kwargs.update({'host': options.deviceIP, 'port': options.devicePort}) dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) options = parser.verifyRemoteOptions(options) if (options == None): print "ERROR: Invalid options specified, use --help for a list of valid options" sys.exit(1) # TODO fix exception if not options.ignoreWindowSize: parts = dm.getInfo('screen')['screen'][0].split() width = int(parts[0].split(':')[1]) height = int(parts[1].split(':')[1]) if (width < 1366 or height < 1050): print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) return 1 auto.setProduct("b2g") auto.test_script = os.path.join(SCRIPT_DIRECTORY, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GReftest(auto, dm, options, SCRIPT_DIRECTORY) options = parser.verifyCommonOptions(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent); auto.setRemoteLog(options.remoteLogFile) auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot manifest = args[0] if os.path.exists(os.path.join(SCRIPT_DIRECTORY, args[0])): manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0]) elif os.path.exists(args[0]): manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/') manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath) else: print "ERROR: Could not find test manifest '%s'" % manifest return 1 # Start the webserver retVal = 1 try: retVal = reftest.startWebServer(options) if retVal: return retVal procName = options.app.split('/')[-1] if (dm.processExist(procName)): dm.killProcess(procName) cmdlineArgs = ["-reftest", manifest] if getattr(options, 'bootstrap', False): cmdlineArgs = [] retVal = reftest.runTests(manifest, options, cmdlineArgs) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() reftest.stopWebServer(options) try: reftest.cleanup(None) except: pass return 1 reftest.stopWebServer(options) return retVal
def run_remote_reftests(parser, options): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) # create our Marionette instance kwargs = {} if options.emulator: kwargs['emulator'] = options.emulator auto.setEmulator(True) if options.noWindow: kwargs['noWindow'] = True if options.geckoPath: kwargs['gecko_path'] = options.geckoPath if options.logdir: kwargs['logdir'] = options.logdir if options.busybox: kwargs['busybox'] = options.busybox if options.symbolsPath: kwargs['symbols_path'] = options.symbolsPath if options.emulator_res: kwargs['emulator_res'] = options.emulator_res if options.b2gPath: kwargs['homedir'] = options.b2gPath if options.marionette: host,port = options.marionette.split(':') kwargs['host'] = host kwargs['port'] = int(port) if options.adb_path: kwargs['adb_path'] = options.adb_path marionette = Marionette(**kwargs) auto.marionette = marionette if options.emulator: dm = marionette.emulator.dm else: # create the DeviceManager kwargs = {'adbPath': options.adb_path, 'deviceRoot': options.remoteTestRoot} if options.deviceIP: kwargs.update({'host': options.deviceIP, 'port': options.devicePort}) dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) parser.validate_remote(options, auto) # TODO fix exception if not options.ignoreWindowSize: parts = dm.getInfo('screen')['screen'][0].split() width = int(parts[0].split(':')[1]) height = int(parts[1].split(':')[1]) if (width < 1366 or height < 1050): print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) return 1 auto.setProduct("b2g") auto.test_script = os.path.join(here, 'b2g_start_script.js') auto.test_script_args = [options.remoteWebServer, options.httpPort] reftest = B2GRemoteReftest(auto, dm, options, here) parser.validate(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent); auto.setRemoteLog(options.remoteLogFile) auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) # Hack in a symbolic link for jsreftest os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) # Start the webserver retVal = 1 try: retVal = reftest.startWebServer(options) if retVal: return retVal procName = options.app.split('/')[-1] if (dm.processExist(procName)): dm.killProcess(procName) retVal = reftest.runTests(options.tests, options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() reftest.stopWebServer(options) try: reftest.cleanup(None) except: pass return 1 reftest.stopWebServer(options) return retVal
class AndroidEmulator(object): """ Support running the Android emulator with an AVD from Mozilla test automation. Example usage: emulator = AndroidEmulator() if not emulator.is_running() and emulator.is_available(): if not emulator.check_avd(): warn("this may take a while...") emulator.update_avd() emulator.start() emulator.wait_for_start() emulator.wait() """ def __init__(self, avd_type='4.3', verbose=False, substs=None, device_serial=None): global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] adb_path = _find_sdk_exe(substs, 'adb', False) if not adb_path: adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1, deviceSerial=device_serial) self.dm.default_timeout = 10 _log_debug("Emulator created with type %s" % self.avd_type) def __del__(self): if self.emulator_log: self.emulator_log.close() def is_running(self): """ Returns True if the Android emulator is running. """ for proc in psutil.process_iter(): name = proc.name() # On some platforms, "emulator" may start an emulator with # process name "emulator64-arm" or similar. if name and name.startswith('emulator'): return True return False def is_available(self): """ Returns True if an emulator executable is found. """ found = False emulator_path = _find_sdk_exe(self.substs, 'emulator', True) if emulator_path: self.emulator_path = emulator_path found = True return found def check_avd(self, force=False): """ Determine if the AVD is already installed locally. (This is usually used to determine if update_avd() is likely to require a download; it is a convenient way of determining whether a 'this may take a while' warning is warranted.) Returns True if the AVD is installed. """ avd = os.path.join(EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') if force and os.path.exists(avd): shutil.rmtree(avd) if os.path.exists(avd): _log_debug("AVD found at %s" % avd) return True return False def update_avd(self, force=False): """ If required, update the AVD via tooltool. If the AVD directory is not found, or "force" is requested, download the tooltool manifest associated with the AVD and then invoke tooltool.py on the manifest. tooltool.py will download the required archive (unless already present in the local tooltool cache) and install the AVD. """ avd = os.path.join(EMULATOR_HOME_DIR, 'avd', self.avd_info.name + '.avd') if force and os.path.exists(avd): shutil.rmtree(avd) if not os.path.exists(avd): _download_file(TOOLTOOL_URL, 'tooltool.py', EMULATOR_HOME_DIR) url = '%s/%s' % (TRY_URL, self.avd_info.tooltool_manifest) _download_file(url, 'releng.manifest', EMULATOR_HOME_DIR) _tooltool_fetch() self._update_avd_paths() def start(self): """ Launch the emulator. """ def outputHandler(line): self.emulator_log.write("<%s>\n" % line) env = os.environ env['ANDROID_AVD_HOME'] = os.path.join(EMULATOR_HOME_DIR, "avd") command = [ self.emulator_path, "-avd", self.avd_info.name, "-port", "5554" ] if self.avd_info.extra_args: # -enable-kvm option is not valid on OSX if _get_host_platform( ) == 'macosx64' and '-enable-kvm' in self.avd_info.extra_args: self.avd_info.extra_args.remove('-enable-kvm') command += self.avd_info.extra_args log_path = os.path.join(EMULATOR_HOME_DIR, 'emulator.log') self.emulator_log = open(log_path, 'w') _log_debug("Starting the emulator with this command: %s" % ' '.join(command)) _log_debug("Emulator output will be written to '%s'" % log_path) self.proc = ProcessHandler(command, storeOutput=False, processOutputLine=outputHandler, env=env) self.proc.run() _log_debug("Emulator started with pid %d" % int(self.proc.proc.pid)) def wait_for_start(self): """ Verify that the emulator is running, the emulator device is visible to adb, and Android has booted. """ if not self.proc: _log_warning("Emulator not started!") return False if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Waiting for device status...") while (('emulator-5554', 'device') not in self.dm.devices()): time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Device status verified.") _log_debug("Checking that Android has booted...") complete = False while (not complete): output = '' try: output = self.dm.shellCheckOutput( ['getprop', 'sys.boot_completed'], timeout=5) except DMError: # adb not yet responding...keep trying pass if output.strip() == '1': complete = True else: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False _log_debug("Android boot status verified.") if not self._verify_emulator(): return False if self.avd_info.uses_sut: if not self._verify_sut(): return False return True def wait(self): """ Wait for the emulator to close. If interrupted, close the emulator. """ try: self.proc.wait() except: if self.proc.poll() is None: self.cleanup() return self.proc.poll() def cleanup(self): """ Close the emulator. """ self.proc.kill(signal.SIGTERM) def get_avd_description(self): """ Return the human-friendly description of this AVD. """ return self.avd_info.description def _update_avd_paths(self): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") ini_file = os.path.join(avd_path, "test-1.ini") ini_file_new = os.path.join(avd_path, self.avd_info.name + ".ini") os.rename(ini_file, ini_file_new) avd_dir = os.path.join(avd_path, "test-1.avd") avd_dir_new = os.path.join(avd_path, self.avd_info.name + ".avd") os.rename(avd_dir, avd_dir_new) self._replace_ini_contents(ini_file_new) def _replace_ini_contents(self, path): with open(path, "r") as f: lines = f.readlines() with open(path, "w") as f: for line in lines: if line.startswith('path='): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") f.write('path=%s/%s.avd\n' % (avd_path, self.avd_info.name)) elif line.startswith('path.rel='): f.write('path.rel=avd/%s.avd\n' % self.avd_info.name) else: f.write(line) def _telnet_cmd(self, telnet, command): _log_debug(">>> " + command) telnet.write('%s\n' % command) result = telnet.read_until('OK', 10) _log_debug("<<< " + result) return result def _verify_emulator(self): telnet_ok = False tn = None while (not telnet_ok): try: tn = telnetlib.Telnet('localhost', self.avd_info.port, 10) if tn is not None: res = tn.read_until('OK', 10) self._telnet_cmd(tn, 'avd status') if self.avd_info.uses_sut: cmd = 'redir add tcp:%s:%s' % \ (str(self.avd_info.sut_port), str(self.avd_info.sut_port)) self._telnet_cmd(tn, cmd) cmd = 'redir add tcp:%s:%s' % \ (str(self.avd_info.sut_port2), str(self.avd_info.sut_port2)) self._telnet_cmd(tn, cmd) self._telnet_cmd(tn, 'redir list') self._telnet_cmd(tn, 'network status') tn.write('quit\n') tn.read_all() telnet_ok = True else: _log_warning("Unable to connect to port %d" % port) except: _log_warning("Trying again after unexpected exception") finally: if tn is not None: tn.close() if not telnet_ok: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False return telnet_ok def _verify_sut(self): sut_ok = False while (not sut_ok): try: tn = telnetlib.Telnet('localhost', self.avd_info.sut_port, 10) if tn is not None: _log_debug("Connected to port %d" % self.avd_info.sut_port) res = tn.read_until('$>', 10) if res.find('$>') == -1: _log_debug("Unexpected SUT response: %s" % res) else: _log_debug("SUT response: %s" % res) sut_ok = True tn.write('quit\n') tn.read_all() except: _log_debug("Caught exception while verifying sutagent") finally: if tn is not None: tn.close() if not sut_ok: time.sleep(10) if self.proc.proc.poll() is not None: _log_warning("Emulator has already completed!") return False return sut_ok def _get_avd_type(self, requested): if requested in AVD_DICT.keys(): return requested if self.substs: if not self.substs['TARGET_CPU'].startswith('arm'): return 'x86' if self.substs['MOZ_ANDROID_MIN_SDK_VERSION'] == '9': return '2.3' return '4.3'
def uninstall(adb="adb"): dm = DeviceManagerADB(adbPath=adb) dm.remount() if dm.dirExists(INSTALL_DIR): dm.removeDir(INSTALL_DIR)
def configure_devices(self): """ Ensure devices.ini is set up. """ keep_going = True device_ini = os.path.join(self.config['base-dir'], 'devices.ini') if os.path.exists(device_ini): response = raw_input( "Use existing device configuration at %s? (Y/n) " % device_ini).strip() if not 'n' in response.lower(): self.build_obj.log(logging.INFO, "autophone", {}, "Using device configuration at %s" % device_ini) return keep_going keep_going = False self.build_obj.log(logging.INFO, "autophone", {}, "You must configure at least one Android device before running autophone.") response = raw_input( "Configure devices now? (Y/n) ").strip() if response.lower().startswith('y') or response == '': response = raw_input( "Connect your rooted Android test device(s) with usb and press Enter ") adb_path = 'adb' try: if os.path.exists(self.build_obj.substs["ADB"]): adb_path = self.build_obj.substs["ADB"] except: if self.verbose: self.build_obj.log(logging.ERROR, "autophone", {}, str(sys.exc_info()[0])) # No build environment? try: adb_path = which.which('adb') except which.WhichError: adb_path = raw_input( "adb not found. Enter path to adb: ").strip() if self.verbose: print("Using adb at %s" % adb_path) dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) device_index = 1 try: with open(os.path.join(self.config['base-dir'], 'devices.ini'), 'w') as f: for device in dm.devices(): serial = device[0] if self.verify_device(adb_path, serial): f.write("[device-%d]\nserialno=%s\n" % (device_index, serial)) device_index += 1 self.build_obj.log(logging.INFO, "autophone", {}, "Added '%s' to device configuration." % serial) keep_going = True else: self.build_obj.log(logging.WARNING, "autophone", {}, "Device '%s' is not rooted - skipping" % serial) except: self.build_obj.log(logging.ERROR, "autophone", {}, "Failed to get list of connected Android devices.") if self.verbose: self.build_obj.log(logging.ERROR, "autophone", {}, str(sys.exc_info()[0])) keep_going = False if device_index <= 1: self.build_obj.log(logging.ERROR, "autophone", {}, "No devices configured! (Can you see your rooted test device(s) in 'adb devices'?") keep_going = False if keep_going: self.config['devices-configured'] = True return keep_going
def dm(self): if not self._dm: self._dm = DeviceManagerADB(adbPath=self.adb_path) return self._dm
def dm(self): if not self._dm: self._dm = DeviceManagerADB(adbPath=self.adb, autoconnect=False, deviceRoot=self.remote_test_root) return self._dm