Bug 811388 - Update mozdevice to 0.15, update consumers;r=ahal

This commit is contained in:
William Lachance 2012-11-14 09:49:04 -08:00
parent 807a0d0fb3
commit 5a3130a3ae
8 changed files with 143 additions and 121 deletions

View File

@ -294,9 +294,9 @@ class B2GRemoteAutomation(Automation):
# into a queue. The lines in this queue are # into a queue. The lines in this queue are
# retrieved and returned by accessing the stdout property of # retrieved and returned by accessing the stdout property of
# this class. # this class.
cmd = [self.dm.adbPath] cmd = [self.dm._adbPath]
if self.dm.deviceSerial: if self.dm._deviceSerial:
cmd.extend(['-s', self.dm.deviceSerial]) cmd.extend(['-s', self.dm._deviceSerial])
cmd.append('shell') cmd.append('shell')
cmd.append('/system/bin/b2g.sh') cmd.append('/system/bin/b2g.sh')
proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue)) proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue))

View File

@ -253,7 +253,7 @@ class B2GReftest(RefTest):
# Restore the original user.js. # Restore the original user.js.
self._devicemanager._checkCmdAs(['shell', 'rm', '-f', self.userJS]) self._devicemanager._checkCmdAs(['shell', 'rm', '-f', self.userJS])
if self._devicemanager.useDDCopy: if self._devicemanager._useDDCopy:
self._devicemanager._checkCmdAs(['shell', 'dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS]) self._devicemanager._checkCmdAs(['shell', 'dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS])
else: else:
self._devicemanager._checkCmdAs(['shell', 'cp', '%s.orig' % self.userJS, self.userJS]) self._devicemanager._checkCmdAs(['shell', 'cp', '%s.orig' % self.userJS, self.userJS])
@ -435,7 +435,7 @@ user_pref("capability.principal.codebase.p2.id", "http://%s:%s");
# In B2G, user.js is always read from /data/local, not the profile # In B2G, user.js is always read from /data/local, not the profile
# directory. Backup the original user.js first so we can restore it. # directory. Backup the original user.js first so we can restore it.
self._devicemanager._checkCmdAs(['shell', 'rm', '-f', '%s.orig' % self.userJS]) self._devicemanager._checkCmdAs(['shell', 'rm', '-f', '%s.orig' % self.userJS])
if self._devicemanager.useDDCopy: if self._devicemanager._useDDCopy:
self._devicemanager._checkCmdAs(['shell', 'dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS]) self._devicemanager._checkCmdAs(['shell', 'dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS])
else: else:
self._devicemanager._checkCmdAs(['shell', 'cp', self.userJS, '%s.orig' % self.userJS]) self._devicemanager._checkCmdAs(['shell', 'cp', self.userJS, '%s.orig' % self.userJS])

View File

@ -212,7 +212,7 @@ class B2GMochitest(Mochitest):
self.originalProfilesIni = None self.originalProfilesIni = None
def copyRemoteFile(self, src, dest): def copyRemoteFile(self, src, dest):
if self._dm.useDDCopy: if self._dm._useDDCopy:
self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src,'of=%s' % dest]) self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src,'of=%s' % dest])
else: else:
self._dm._checkCmdAs(['shell', 'cp', src, dest]) self._dm._checkCmdAs(['shell', 'cp', src, dest])

View File

@ -33,7 +33,7 @@ def abstractmethod(method):
class DeviceManager: class DeviceManager:
logcatNeedsRoot = True _logcatNeedsRoot = True
@abstractmethod @abstractmethod
def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False): def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
@ -362,13 +362,15 @@ class DeviceManager:
return 0 return 0
def getIP(self, conn_type='eth0'): def getIP(self, interfaces=['eth0', 'wlan0']):
""" """
Gets the IP of the device, or None if no connection exists. Gets the IP of the device, or None if no connection exists.
""" """
match = re.match(r"%s: ip (\S+)" % conn_type, self.shellCheckOutput(['ifconfig', conn_type])) for interface in interfaces:
if match: match = re.match(r"%s: ip (\S+)" % interface,
return match.group(1) self.shellCheckOutput(['ifconfig', interface]))
if match:
return match.group(1)
@abstractmethod @abstractmethod
def unpackFile(self, file_path, dest_dir=None): def unpackFile(self, file_path, dest_dir=None):
@ -489,7 +491,7 @@ class DeviceManager:
#TODO: spawn this off in a separate thread/process so we can collect all the logcat information #TODO: spawn this off in a separate thread/process so we can collect all the logcat information
# Right now this is just clearing the logcat so we can only see what happens after this call. # Right now this is just clearing the logcat so we can only see what happens after this call.
self.shellCheckOutput(['/system/bin/logcat', '-c'], root=self.logcatNeedsRoot) self.shellCheckOutput(['/system/bin/logcat', '-c'], root=self._logcatNeedsRoot)
def getLogcat(self, filterSpecs=["dalvikvm:S", "ConnectivityService:S", def getLogcat(self, filterSpecs=["dalvikvm:S", "ConnectivityService:S",
"WifiMonitor:S", "WifiStateTracker:S", "WifiMonitor:S", "WifiStateTracker:S",
@ -501,7 +503,7 @@ class DeviceManager:
""" """
cmdline = ["/system/bin/logcat", "-v", format, "-d"] + filterSpecs cmdline = ["/system/bin/logcat", "-v", format, "-d"] + filterSpecs
lines = self.shellCheckOutput(cmdline, lines = self.shellCheckOutput(cmdline,
root=self.logcatNeedsRoot).split('\r') root=self._logcatNeedsRoot).split('\r')
for regex in filterOutRegexps: for regex in filterOutRegexps:
lines = [line for line in lines if not re.search(regex, line)] lines = [line for line in lines if not re.search(regex, line)]

View File

@ -6,44 +6,44 @@ import subprocess
from devicemanager import DeviceManager, DMError, _pop_last_line from devicemanager import DeviceManager, DMError, _pop_last_line
import re import re
import os import os
import shutil
import tempfile import tempfile
import time import time
class DeviceManagerADB(DeviceManager): class DeviceManagerADB(DeviceManager):
_haveRootShell = False
_haveSu = False
_useRunAs = False
_useDDCopy = False
_useZip = False
_logcatNeedsRoot = False
_pollingInterval = 0.01
_packageName = None
_tempDir = None
default_timeout = 300
def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec', def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec',
adbPath='adb', deviceSerial=None, deviceRoot=None, **kwargs): adbPath='adb', deviceSerial=None, deviceRoot=None, **kwargs):
self.host = host self.host = host
self.port = port self.port = port
self.retrylimit = retrylimit self.retrylimit = retrylimit
self.retries = 0
self._sock = None
self.haveRootShell = False
self.haveSu = False
self.useRunAs = False
self.useDDCopy = False
self.useZip = False
self.logcatNeedsRoot = False
self.packageName = None
self.tempDir = None
self.deviceRoot = deviceRoot self.deviceRoot = deviceRoot
self.default_timeout = 300
self.pollingInterval = 0.01
# the path to adb, or 'adb' to assume that it's on the PATH # the path to adb, or 'adb' to assume that it's on the PATH
self.adbPath = adbPath self._adbPath = adbPath
# The serial number of the device to use with adb, used in cases # The serial number of the device to use with adb, used in cases
# where multiple devices are being managed by the same adb instance. # where multiple devices are being managed by the same adb instance.
self.deviceSerial = deviceSerial self._deviceSerial = deviceSerial
if packageName == 'fennec': if packageName == 'fennec':
if os.getenv('USER'): if os.getenv('USER'):
self.packageName = 'org.mozilla.fennec_' + os.getenv('USER') self._packageName = 'org.mozilla.fennec_' + os.getenv('USER')
else: else:
self.packageName = 'org.mozilla.fennec_' self._packageName = 'org.mozilla.fennec_'
elif packageName: elif packageName:
self.packageName = packageName self._packageName = packageName
# verify that we can run the adb command. can't continue otherwise # verify that we can run the adb command. can't continue otherwise
self._verifyADB() self._verifyADB()
@ -96,7 +96,7 @@ class DeviceManagerADB(DeviceManager):
# always. :( # always. :(
# If requested to run as root, check that we can actually do that # If requested to run as root, check that we can actually do that
if root and not self.haveRootShell and not self.haveSu: if root and not self._haveRootShell and not self._haveSu:
raise DMError("Shell command '%s' requested to run as root but root " raise DMError("Shell command '%s' requested to run as root but root "
"is not available on this device. Root your device or " "is not available on this device. Root your device or "
"refactor the test/harness to not require root." % "refactor the test/harness to not require root." %
@ -105,7 +105,7 @@ class DeviceManagerADB(DeviceManager):
# Getting the return code is more complex than you'd think because adb # Getting the return code is more complex than you'd think because adb
# doesn't actually return the return code from a process, so we have to # doesn't actually return the return code from a process, so we have to
# capture the output to get it # capture the output to get it
if root and not self.haveRootShell: if root and not self._haveRootShell:
cmdline = "su -c \"%s\"" % self._escapedCommandLine(cmd) cmdline = "su -c \"%s\"" % self._escapedCommandLine(cmd)
else: else:
cmdline = self._escapedCommandLine(cmd) cmdline = self._escapedCommandLine(cmd)
@ -119,9 +119,9 @@ class DeviceManagerADB(DeviceManager):
cmdline = envstr + "; " + cmdline cmdline = envstr + "; " + cmdline
# all output should be in stdout # all output should be in stdout
args=[self.adbPath] args=[self._adbPath]
if self.deviceSerial: if self._deviceSerial:
args.extend(['-s', self.deviceSerial]) args.extend(['-s', self._deviceSerial])
args.extend(["shell", cmdline]) args.extend(["shell", cmdline])
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -133,7 +133,7 @@ class DeviceManagerADB(DeviceManager):
start_time = time.time() start_time = time.time()
ret_code = proc.poll() ret_code = proc.poll()
while ((time.time() - start_time) <= timeout) and ret_code == None: while ((time.time() - start_time) <= timeout) and ret_code == None:
time.sleep(self.pollingInterval) time.sleep(self._pollingInterval)
ret_code = proc.poll() ret_code = proc.poll()
if ret_code == None: if ret_code == None:
proc.kill() proc.kill()
@ -170,10 +170,10 @@ class DeviceManagerADB(DeviceManager):
raise DMError("Attempted to push a file (%s) to a directory (%s)!" % raise DMError("Attempted to push a file (%s) to a directory (%s)!" %
(localname, destname)) (localname, destname))
if self.useRunAs: if self._useRunAs:
remoteTmpFile = self.getTempDir() + "/" + os.path.basename(localname) remoteTmpFile = self.getTempDir() + "/" + os.path.basename(localname)
self._checkCmd(["push", os.path.realpath(localname), remoteTmpFile]) self._checkCmd(["push", os.path.realpath(localname), remoteTmpFile])
if self.useDDCopy: if self._useDDCopy:
self.shellCheckOutput(["dd", "if=" + remoteTmpFile, "of=" + destname]) self.shellCheckOutput(["dd", "if=" + remoteTmpFile, "of=" + destname])
else: else:
self.shellCheckOutput(["cp", remoteTmpFile, destname]) self.shellCheckOutput(["cp", remoteTmpFile, destname])
@ -195,11 +195,11 @@ class DeviceManagerADB(DeviceManager):
""" """
# adb "push" accepts a directory as an argument, but if the directory # adb "push" accepts a directory as an argument, but if the directory
# contains symbolic links, the links are pushed, rather than the linked # contains symbolic links, the links are pushed, rather than the linked
# files; we either zip/unzip or push file-by-file to get around this # files; we either zip/unzip or re-copy the directory into a temporary
# limitation # one to get around this limitation
if not self.dirExists(remoteDir): if not self.dirExists(remoteDir):
self.mkDirs(remoteDir+"/x") self.mkDirs(remoteDir+"/x")
if self.useZip: if self._useZip:
try: try:
localZip = tempfile.mktemp() + ".zip" localZip = tempfile.mktemp() + ".zip"
remoteZip = remoteDir + "/adbdmtmp.zip" remoteZip = remoteDir + "/adbdmtmp.zip"
@ -212,24 +212,15 @@ class DeviceManagerADB(DeviceManager):
raise Exception("unzip failed, or permissions error") raise Exception("unzip failed, or permissions error")
except: except:
print "zip/unzip failure: falling back to normal push" print "zip/unzip failure: falling back to normal push"
self.useZip = False self._useZip = False
self.pushDir(localDir, remoteDir) self.pushDir(localDir, remoteDir)
else: else:
for root, dirs, files in os.walk(localDir, followlinks=True): tmpDir = tempfile.mkdtemp()
relRoot = os.path.relpath(root, localDir) # copytree's target dir must not already exist, so create a subdir
for f in files: tmpDirTarget = os.path.join(tmpDir, "tmp")
localFile = os.path.join(root, f) shutil.copytree(localDir, tmpDirTarget)
remoteFile = remoteDir + "/" self._checkCmd(["push", tmpDirTarget, remoteDir])
if relRoot != ".": shutil.rmtree(tmpDir)
remoteFile = remoteFile + relRoot + "/"
remoteFile = remoteFile + f
self.pushFile(localFile, remoteFile)
for d in dirs:
targetDir = remoteDir + "/"
if relRoot != ".":
targetDir = targetDir + relRoot + "/"
targetDir = targetDir + d
self.mkDir(targetDir)
def dirExists(self, remotePath): def dirExists(self, remotePath):
""" """
@ -418,7 +409,7 @@ class DeviceManagerADB(DeviceManager):
if (len(errl) == 1): if (len(errl) == 1):
if (((errl[0].find("Permission denied") != -1) if (((errl[0].find("Permission denied") != -1)
or (errl[0].find("does not exist") != -1)) or (errl[0].find("does not exist") != -1))
and self.useRunAs): and self._useRunAs):
# If we lack permissions to read but have run-as, then we should try # If we lack permissions to read but have run-as, then we should try
# to copy the file to a world-readable location first before attempting # to copy the file to a world-readable location first before attempting
# to pull it again. # to pull it again.
@ -544,11 +535,11 @@ class DeviceManagerADB(DeviceManager):
""" """
# Cache result to speed up operations depending # Cache result to speed up operations depending
# on the temporary directory. # on the temporary directory.
if not self.tempDir: if not self._tempDir:
self.tempDir = self.getDeviceRoot() + "/tmp" self._tempDir = self.getDeviceRoot() + "/tmp"
self.mkDir(self.tempDir) self.mkDir(self._tempDir)
return self.tempDir return self._tempDir
def getAppRoot(self, packageName): def getAppRoot(self, packageName):
""" """
@ -561,10 +552,10 @@ class DeviceManagerADB(DeviceManager):
return None return None
if (packageName and self.dirExists('/data/data/' + packageName)): if (packageName and self.dirExists('/data/data/' + packageName)):
self.packageName = packageName self._packageName = packageName
return '/data/data/' + packageName return '/data/data/' + packageName
elif (self.packageName and self.dirExists('/data/data/' + self.packageName)): elif (self._packageName and self.dirExists('/data/data/' + self._packageName)):
return '/data/data/' + self.packageName return '/data/data/' + self._packageName
# Failure (either not installed or not a recognized platform) # Failure (either not installed or not a recognized platform)
raise DMError("Failed to get application root for: %s" % packageName) raise DMError("Failed to get application root for: %s" % packageName)
@ -674,27 +665,28 @@ class DeviceManagerADB(DeviceManager):
returns: returncode from subprocess.Popen returns: returncode from subprocess.Popen
""" """
finalArgs = [self.adbPath] finalArgs = [self._adbPath]
if self.deviceSerial: if self._deviceSerial:
finalArgs.extend(['-s', self.deviceSerial]) finalArgs.extend(['-s', self._deviceSerial])
# use run-as to execute commands as the package we're testing if # use run-as to execute commands as the package we're testing if
# possible # possible
if not self.haveRootShell and self.useRunAs and args[0] == "shell" and args[1] != "run-as": if not self._haveRootShell and self._useRunAs and \
args[0] == "shell" and args[1] not in [ "run-as", "am" ]:
args.insert(1, "run-as") args.insert(1, "run-as")
args.insert(2, self.packageName) args.insert(2, self._packageName)
finalArgs.extend(args) finalArgs.extend(args)
return subprocess.Popen(finalArgs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) return subprocess.Popen(finalArgs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _runCmdAs(self, args): def _runCmdAs(self, args):
""" """
Runs a command using adb Runs a command using adb
If self.useRunAs is True, the command is run-as user specified in self.packageName If self._useRunAs is True, the command is run-as user specified in self._packageName
returns: returncode from subprocess.Popen returns: returncode from subprocess.Popen
""" """
if self.useRunAs: if self._useRunAs:
args.insert(1, "run-as") args.insert(1, "run-as")
args.insert(2, self.packageName) args.insert(2, self._packageName)
return self._runCmd(args) return self._runCmd(args)
# timeout is specified in seconds, and if no timeout is given, # timeout is specified in seconds, and if no timeout is given,
@ -708,12 +700,13 @@ class DeviceManagerADB(DeviceManager):
""" """
# use run-as to execute commands as the package we're testing if # use run-as to execute commands as the package we're testing if
# possible # possible
finalArgs = [self.adbPath] finalArgs = [self._adbPath]
if self.deviceSerial: if self._deviceSerial:
finalArgs.extend(['-s', self.deviceSerial]) finalArgs.extend(['-s', self._deviceSerial])
if not self.haveRootShell and self.useRunAs and args[0] == "shell" and args[1] != "run-as": if not self._haveRootShell and self._useRunAs and \
args[0] == "shell" and args[1] not in [ "run-as", "am" ]:
args.insert(1, "run-as") args.insert(1, "run-as")
args.insert(2, self.packageName) args.insert(2, self._packageName)
finalArgs.extend(args) finalArgs.extend(args)
if not timeout: if not timeout:
# We are asserting that all commands will complete in this time unless otherwise specified # We are asserting that all commands will complete in this time unless otherwise specified
@ -724,7 +717,7 @@ class DeviceManagerADB(DeviceManager):
start_time = time.time() start_time = time.time()
ret_code = proc.poll() ret_code = proc.poll()
while ((time.time() - start_time) <= timeout) and ret_code == None: while ((time.time() - start_time) <= timeout) and ret_code == None:
time.sleep(self.pollingInterval) time.sleep(self._pollingInterval)
ret_code = proc.poll() ret_code = proc.poll()
if ret_code == None: if ret_code == None:
proc.kill() proc.kill()
@ -734,14 +727,14 @@ class DeviceManagerADB(DeviceManager):
def _checkCmdAs(self, args, timeout=None): def _checkCmdAs(self, args, timeout=None):
""" """
Runs a command using adb and waits for command to finish Runs a command using adb and waits for command to finish
If self.useRunAs is True, the command is run-as user specified in self.packageName If self._useRunAs is True, the command is run-as user specified in self._packageName
If timeout is specified, the process is killed after <timeout> seconds If timeout is specified, the process is killed after <timeout> seconds
returns: returncode from subprocess.Popen returns: returncode from subprocess.Popen
""" """
if (self.useRunAs): if (self._useRunAs):
args.insert(1, "run-as") args.insert(1, "run-as")
args.insert(2, self.packageName) args.insert(2, self._packageName)
return self._checkCmd(args, timeout) return self._checkCmd(args, timeout)
def chmodDir(self, remoteDir, mask="777"): def chmodDir(self, remoteDir, mask="777"):
@ -767,9 +760,9 @@ class DeviceManagerADB(DeviceManager):
""" """
Check to see if adb itself can be executed. Check to see if adb itself can be executed.
""" """
if self.adbPath != 'adb': if self._adbPath != 'adb':
if not os.access(self.adbPath, os.X_OK): if not os.access(self._adbPath, os.X_OK):
raise DMError("invalid adb path, or adb not executable: %s", self.adbPath) raise DMError("invalid adb path, or adb not executable: %s", self._adbPath)
try: try:
self._checkCmd(["version"]) self._checkCmd(["version"])
@ -780,20 +773,20 @@ class DeviceManagerADB(DeviceManager):
def _verifyDevice(self): def _verifyDevice(self):
# If there is a device serial number, see if adb is connected to it # If there is a device serial number, see if adb is connected to it
if self.deviceSerial: if self._deviceSerial:
deviceStatus = None deviceStatus = None
proc = subprocess.Popen([self.adbPath, "devices"], proc = subprocess.Popen([self._adbPath, "devices"],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
for line in proc.stdout: for line in proc.stdout:
m = re.match('(.+)?\s+(.+)$', line) m = re.match('(.+)?\s+(.+)$', line)
if m: if m:
if self.deviceSerial == m.group(1): if self._deviceSerial == m.group(1):
deviceStatus = m.group(2) deviceStatus = m.group(2)
if deviceStatus == None: if deviceStatus == None:
raise DMError("device not found: %s" % self.deviceSerial) raise DMError("device not found: %s" % self._deviceSerial)
elif deviceStatus != "device": elif deviceStatus != "device":
raise DMError("bad status for device %s: %s" % (self.deviceSerial, deviceStatus)) raise DMError("bad status for device %s: %s" % (self._deviceSerial, deviceStatus))
# Check to see if we can connect to device and run a simple command # Check to see if we can connect to device and run a simple command
try: try:
@ -814,7 +807,7 @@ class DeviceManagerADB(DeviceManager):
data = self._runCmd(["shell", "dd", "-"]).stdout.read() data = self._runCmd(["shell", "dd", "-"]).stdout.read()
if (re.search('unknown operand', data)): if (re.search('unknown operand', data)):
print "'cp' not found, but 'dd' was found as a replacement" print "'cp' not found, but 'dd' was found as a replacement"
self.useDDCopy = True self._useDDCopy = True
return True return True
print "unable to execute 'cp' on device; consider installing busybox from Android Market" print "unable to execute 'cp' on device; consider installing busybox from Android Market"
return False return False
@ -827,28 +820,28 @@ class DeviceManagerADB(DeviceManager):
# echoing conditions encountered by Fennec at run time. # echoing conditions encountered by Fennec at run time.
# Check to see if run-as can be used here, by verifying a # Check to see if run-as can be used here, by verifying a
# file copy via run-as. # file copy via run-as.
self.useRunAs = False self._useRunAs = False
devroot = self.getDeviceRoot() devroot = self.getDeviceRoot()
if (self.packageName and self._isCpAvailable() and devroot): if (self._packageName and self._isCpAvailable() and devroot):
tmpDir = self.getTempDir() tmpDir = self.getTempDir()
# The problem here is that run-as doesn't cause a non-zero exit code # The problem here is that run-as doesn't cause a non-zero exit code
# when failing because of a non-existent or non-debuggable package :( # when failing because of a non-existent or non-debuggable package :(
runAsOut = self._runCmd(["shell", "run-as", self.packageName, "mkdir", devroot + "/sanity"]).communicate()[0] runAsOut = self._runCmd(["shell", "run-as", self._packageName, "mkdir", devroot + "/sanity"]).communicate()[0]
if runAsOut.startswith("run-as:") and ("not debuggable" in runAsOut or "is unknown" in runAsOut): if runAsOut.startswith("run-as:") and ("not debuggable" in runAsOut or "is unknown" in runAsOut):
raise DMError("run-as failed sanity check") raise DMError("run-as failed sanity check")
tmpfile = tempfile.NamedTemporaryFile() tmpfile = tempfile.NamedTemporaryFile()
self._checkCmd(["push", tmpfile.name, tmpDir + "/tmpfile"]) self._checkCmd(["push", tmpfile.name, tmpDir + "/tmpfile"])
if self.useDDCopy: if self._useDDCopy:
self._checkCmd(["shell", "run-as", self.packageName, "dd", "if=" + tmpDir + "/tmpfile", "of=" + devroot + "/sanity/tmpfile"]) self._checkCmd(["shell", "run-as", self._packageName, "dd", "if=" + tmpDir + "/tmpfile", "of=" + devroot + "/sanity/tmpfile"])
else: else:
self._checkCmd(["shell", "run-as", self.packageName, "cp", tmpDir + "/tmpfile", devroot + "/sanity"]) self._checkCmd(["shell", "run-as", self._packageName, "cp", tmpDir + "/tmpfile", devroot + "/sanity"])
if (self.fileExists(devroot + "/sanity/tmpfile")): if (self.fileExists(devroot + "/sanity/tmpfile")):
print "will execute commands via run-as " + self.packageName print "will execute commands via run-as " + self._packageName
self.useRunAs = True self._useRunAs = True
self._checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"]) self._checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
self._checkCmd(["shell", "run-as", self.packageName, "rm", "-r", devroot + "/sanity"]) self._checkCmd(["shell", "run-as", self._packageName, "rm", "-r", devroot + "/sanity"])
def _checkForRoot(self): def _checkForRoot(self):
# Check whether we _are_ root by default (some development boards work # Check whether we _are_ root by default (some development boards work
@ -857,7 +850,7 @@ class DeviceManagerADB(DeviceManager):
proc = self._runCmd(["shell", "id"]) proc = self._runCmd(["shell", "id"])
data = proc.stdout.read() data = proc.stdout.read()
if data.find('uid=0(root)') >= 0: if data.find('uid=0(root)') >= 0:
self.haveRootShell = True self._haveRootShell = True
# if this returns true, we don't care about su # if this returns true, we don't care about su
return return
@ -876,7 +869,7 @@ class DeviceManagerADB(DeviceManager):
data = proc.stdout.read() data = proc.stdout.read()
if data.find('uid=0(root)') >= 0: if data.find('uid=0(root)') >= 0:
self.haveSu = True self._haveSu = True
def _isUnzipAvailable(self): def _isUnzipAvailable(self):
data = self._runCmdAs(["shell", "unzip"]).stdout.read() data = self._runCmdAs(["shell", "unzip"]).stdout.read()
@ -896,9 +889,9 @@ class DeviceManagerADB(DeviceManager):
# If "zip" can be run locally, and "unzip" can be run remotely, then pushDir # If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
# can use these to push just one file per directory -- a significant # can use these to push just one file per directory -- a significant
# optimization for large directories. # optimization for large directories.
self.useZip = False self._useZip = False
if (self._isUnzipAvailable() and self._isLocalZipAvailable()): if (self._isUnzipAvailable() and self._isLocalZipAvailable()):
print "will use zip to push directories" print "will use zip to push directories"
self.useZip = True self._useZip = True
else: else:
raise DMError("zip not available") raise DMError("zip not available")

View File

@ -18,11 +18,11 @@ from distutils.version import StrictVersion
class DeviceManagerSUT(DeviceManager): class DeviceManagerSUT(DeviceManager):
debug = 2 debug = 2
base_prompt = '$>' _base_prompt = '$>'
base_prompt_re = '\$\>' _base_prompt_re = '\$\>'
prompt_sep = '\x00' _prompt_sep = '\x00'
prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')' _prompt_regex = '.*(' + _base_prompt_re + _prompt_sep + ')'
agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)') _agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
default_timeout = 300 default_timeout = 300
def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None, **kwargs): def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None, **kwargs):
@ -61,7 +61,7 @@ class DeviceManagerSUT(DeviceManager):
""" """
take a data blob and strip instances of the prompt '$>\x00' take a data blob and strip instances of the prompt '$>\x00'
""" """
promptre = re.compile(self.prompt_regex + '.*') promptre = re.compile(self._prompt_regex + '.*')
retVal = [] retVal = []
lines = data.split('\n') lines = data.split('\n')
for line in lines: for line in lines:
@ -69,10 +69,10 @@ class DeviceManagerSUT(DeviceManager):
try: try:
while (promptre.match(line)): while (promptre.match(line)):
foundPrompt = True foundPrompt = True
pieces = line.split(self.prompt_sep) pieces = line.split(self._prompt_sep)
index = pieces.index('$>') index = pieces.index('$>')
pieces.pop(index) pieces.pop(index)
line = self.prompt_sep.join(pieces) line = self._prompt_sep.join(pieces)
except(ValueError): except(ValueError):
pass pass
@ -141,7 +141,7 @@ class DeviceManagerSUT(DeviceManager):
return outputfile.read() return outputfile.read()
def _doCmds(self, cmdlist, outputfile, timeout): def _doCmds(self, cmdlist, outputfile, timeout):
promptre = re.compile(self.prompt_regex + '$') promptre = re.compile(self._prompt_regex + '$')
shouldCloseSocket = False shouldCloseSocket = False
if not timeout: if not timeout:
@ -242,7 +242,7 @@ class DeviceManagerSUT(DeviceManager):
# If something goes wrong in the agent it will send back a string that # If something goes wrong in the agent it will send back a string that
# starts with '##AGENT-WARNING##' # starts with '##AGENT-WARNING##'
if not commandFailed: if not commandFailed:
errorMatch = self.agentErrorRE.match(data) errorMatch = self._agentErrorRE.match(data)
if errorMatch: if errorMatch:
# We still need to consume the prompt, so raise an error after # We still need to consume the prompt, so raise an error after
# draining the rest of the buffer. # draining the rest of the buffer.
@ -450,11 +450,20 @@ class DeviceManagerSUT(DeviceManager):
for line in data.splitlines(): for line in data.splitlines():
if line: if line:
pidproc = line.strip().split() pidproc = line.strip().split()
if (len(pidproc) == 2): try:
processTuples += [[pidproc[0], pidproc[1]]] if (len(pidproc) == 2):
elif (len(pidproc) == 3): processTuples += [[pidproc[0], pidproc[1]]]
#android returns <userID> <procID> <procName> elif (len(pidproc) == 3):
processTuples += [[int(pidproc[1]), pidproc[2], int(pidproc[0])]] # android returns <userID> <procID> <procName>
processTuples += [[int(pidproc[1]), pidproc[2], int(pidproc[0])]]
else:
# unexpected format
raise ValueError
except ValueError:
print "ERROR: Unable to parse process list (bug 805969)"
print "Line: %s\nFull output of process list:\n%s" % (line, data)
raise DMError("Invalid process line: %s" % line)
return processTuples return processTuples
def fireProcess(self, appname, failIfRunning=False): def fireProcess(self, appname, failIfRunning=False):
@ -596,7 +605,7 @@ class DeviceManagerSUT(DeviceManager):
buf += data buf += data
return buf return buf
prompt = self.base_prompt + self.prompt_sep prompt = self._base_prompt + self._prompt_sep
buf = '' buf = ''
# expected return value: # expected return value:

View File

@ -5,7 +5,7 @@
import os import os
from setuptools import setup from setuptools import setup
PACKAGE_VERSION = '0.14' PACKAGE_VERSION = '0.15'
# take description from README # take description from README
here = os.path.dirname(os.path.abspath(__file__)) here = os.path.dirname(os.path.abspath(__file__))

View File

@ -8,6 +8,10 @@ class PsTest(unittest.TestCase):
"10029 549 com.android.launcher\n" "10029 549 com.android.launcher\n"
"10066 1198 com.twitter.android")] "10066 1198 com.twitter.android")]
bad_pscommands = [('ps',
"abcdef 549 com.android.launcher\n"
"10066 1198 com.twitter.android")]
def test_processList(self): def test_processList(self):
a = MockAgent(self, a = MockAgent(self,
commands=self.pscommands) commands=self.pscommands)
@ -19,6 +23,20 @@ class PsTest(unittest.TestCase):
a.wait() a.wait()
def test_badProcessList(self):
a = MockAgent(self,
commands=self.bad_pscommands)
d = mozdevice.DroidSUT("127.0.0.1", port=a.port)
exceptionTriggered = False
try:
d.getProcessList()
except mozdevice.DMError:
exceptionTriggered = True
self.assertTrue(exceptionTriggered)
a.wait()
def test_processExist(self): def test_processExist(self):
for i in [('com.android.launcher', 549), for i in [('com.android.launcher', 549),
('com.fennec.android', None)]: ('com.fennec.android', None)]: