Bug 808719 - Mirror over mozdevice 0.14;r=jmaher
authorWilliam Lachance <wlachance@mozilla.com>
Mon, 05 Nov 2012 15:18:54 -0800
changeset 112358 613bfe02f0c1096027e73238a9fcc27ee480531e
parent 112357 4cee05d5b1ce84770ad35222f7962289c323304f
child 112359 c697c428739d1014d81e7e8b0afe8b28f5a08642
push id23812
push useremorley@mozilla.com
push dateTue, 06 Nov 2012 14:01:34 +0000
treeherdermozilla-central@f4aeed115e54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher
bugs808719
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 808719 - Mirror over mozdevice 0.14;r=jmaher
testing/mozbase/mozdevice/mozdevice/devicemanager.py
testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
testing/mozbase/mozdevice/setup.py
--- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
@@ -28,16 +28,18 @@ def abstractmethod(method):
     def not_implemented(*args, **kwargs):
         raise NotImplementedError('Abstract method %s at File "%s", line %s '
                                    'should be implemented by a concrete class' %
                                    (repr(method), filename, line))
     return not_implemented
 
 class DeviceManager:
 
+    logcatNeedsRoot = True
+
     @abstractmethod
     def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
         """
         Executes shell command on device and returns exit code
 
         cmd - Command string to execute
         outputfile - File to store output
         env - Environment to pass to exec command
@@ -211,23 +213,19 @@ class DeviceManager:
         Returns contents of remoteFile using the "pull" command.
 
         returns:
           success: output of pullfile, string
           failure: None
         """
 
     @abstractmethod
-    def getFile(self, remoteFile, localFile = ''):
+    def getFile(self, remoteFile, localFile):
         """
         Copy file from device (remoteFile) to host (localFile)
-
-        returns:
-          success: contents of file, string
-          failure: None
         """
 
     @abstractmethod
     def getDirectory(self, remoteDir, localDir, checkDir=True):
         """
         Copy directory structure from device (remoteDir) to host (localDir)
 
         returns:
@@ -486,32 +484,34 @@ class DeviceManager:
 
     def recordLogcat(self):
         """
         Clears the logcat file making it easier to view specific events
         """
         #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.
-        buf = StringIO.StringIO()
-        self.shell(['/system/bin/logcat', '-c'], buf, root=True)
-
-    def getLogcat(self):
-        """
-        Returns the contents of the logcat file as a string
+        self.shellCheckOutput(['/system/bin/logcat', '-c'], root=self.logcatNeedsRoot)
 
-        returns:
-          success: contents of logcat, string 
-          failure: None
+    def getLogcat(self, filterSpecs=["dalvikvm:S", "ConnectivityService:S",
+                                      "WifiMonitor:S", "WifiStateTracker:S",
+                                      "wpa_supplicant:S", "NetworkStateTracker:S"],
+                  format="time",
+                  filterOutRegexps=[]):
+        """
+        Returns the contents of the logcat file as a list of strings
         """
-        buf = StringIO.StringIO()
-        if self.shell(["/system/bin/logcat", "-d", "dalvikvm:S", "ConnectivityService:S", "WifiMonitor:S", "WifiStateTracker:S", "wpa_supplicant:S", "NetworkStateTracker:S"], buf, root=True) != 0:
-            return None
+        cmdline = ["/system/bin/logcat", "-v", format, "-d"] + filterSpecs
+        lines = self.shellCheckOutput(cmdline,
+                                      root=self.logcatNeedsRoot).split('\r')
 
-        return str(buf.getvalue()[0:-1]).rstrip().split('\r')
+        for regex in filterOutRegexps:
+            lines = [line for line in lines if not re.search(regex, line)]
+
+        return lines
 
     @staticmethod
     def _writePNG(buf, width, height):
         """
         Method for writing a PNG from a buffer, used by getScreenshot on older devices
         Based on: http://code.activestate.com/recipes/577443-write-a-png-image-in-native-python/
         """
         width_byte_4 = width * 4
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -18,20 +18,22 @@ class DeviceManagerADB(DeviceManager):
         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.default_timeout = 300
+        self.pollingInterval = 0.01
 
         # the path to adb, or 'adb' to assume that it's on the PATH
         self.adbPath = adbPath
 
         # The serial number of the device to use with adb, used in cases
         # where multiple devices are being managed by the same adb instance.
         self.deviceSerial = deviceSerial
 
@@ -126,17 +128,17 @@ class DeviceManagerADB(DeviceManager):
         if not timeout:
             # We are asserting that all commands will complete in this time unless otherwise specified
             timeout = self.default_timeout
 
         timeout = int(timeout)
         start_time = time.time()
         ret_code = proc.poll()
         while ((time.time() - start_time) <= timeout) and ret_code == None:
-            time.sleep(1)
+            time.sleep(self.pollingInterval)
             ret_code = proc.poll()
         if ret_code == None:
             proc.kill()
             raise DMError("Timeout exceeded for shell call")
         (stdout, stderr) = proc.communicate()
         outputfile.write(stdout.rstrip('\n'))
 
         lastline = _pop_last_line(outputfile)
@@ -266,24 +268,17 @@ class DeviceManagerADB(DeviceManager):
         """
         return self._runCmd(["shell", "rmdir", remoteDir]).stdout.read()
 
     def removeDir(self, remoteDir):
         """
         Does a recursive delete of directory on the device: rm -Rf remoteDir
         """
         if (self.dirExists(remoteDir)):
-            files = self.listFiles(remoteDir.strip())
-            for f in files:
-                path = remoteDir.strip() + "/" + f.strip()
-                if self.dirExists(path):
-                    self.removeDir(path)
-                else:
-                    self.removeFile(path)
-            self._removeSingleDir(remoteDir.strip())
+            self._runCmd(["shell", "rm", "-r", remoteDir])
         else:
             self.removeFile(remoteDir.strip())
 
     def listFiles(self, rootdir):
         """
         Lists files on the device rootdir
 
         returns array of filenames, ['file1', 'file2', ...]
@@ -391,17 +386,17 @@ class DeviceManagerADB(DeviceManager):
         If forceKill is True, process is killed regardless of state
         """
         procs = self.getProcessList()
         for (pid, name, user) in procs:
             if name == appname:
                 args = ["shell", "kill"]
                 if forceKill:
                     args.append("-9")
-                args.append(pid)
+                args.append(str(pid))
                 p = self._runCmdAs(args)
                 p.communicate()
                 if p.returncode != 0:
                     raise DMError("Error killing process "
                                   "'%s': %s" % (appname, p.stdout.read()))
 
     def catFile(self, remoteFile):
         """
@@ -445,25 +440,21 @@ class DeviceManagerADB(DeviceManager):
         self._runPull(remoteFile, localFile)
 
         f = open(localFile, 'r')
         ret = f.read()
         f.close()
         os.remove(localFile)
         return ret
 
-    def getFile(self, remoteFile, localFile = 'temp.txt'):
+    def getFile(self, remoteFile, localFile):
         """
         Copy file from device (remoteFile) to host (localFile).
         """
-        contents = self.pullFile(remoteFile)
-
-        fhandle = open(localFile, 'wb')
-        fhandle.write(contents)
-        fhandle.close()
+        self._runPull(remoteFile, localFile)
 
     def getDirectory(self, remoteDir, localDir, checkDir=True):
         """
         Copy directory structure from device (remoteDir) to host (localDir)
         """
         self._runCmd(["pull", remoteDir, localDir])
 
     def validateFile(self, remoteFile, localFile):
@@ -607,45 +598,16 @@ class DeviceManagerADB(DeviceManager):
         """
         Returns device time in milliseconds since the epoch
         """
         timestr = self._runCmd(["shell", "date", "+%s"]).stdout.read().strip()
         if (not timestr or not timestr.isdigit()):
             raise DMError("Unable to get current time using date (got: '%s')" % timestr)
         return str(int(timestr)*1000)
 
-    def recordLogcat(self):
-        """
-        Clears the logcat file making it easier to view specific events
-        """
-        # this does not require root privileges with ADB
-        try:
-            self.shellCheckOutput(['/system/bin/logcat', '-c'])
-        except DMError, e:
-            print "DeviceManager: Error recording logcat '%s'" % e.msg
-            # to preserve compat with parent method, just ignore exceptions
-            pass
-
-    def getLogcat(self):
-        """
-        Returns the contents of the logcat file as a string
-
-        returns:
-          success: contents of logcat, string
-          failure: None
-        """
-        # this does not require root privileges with ADB
-        try:
-            output = self.shellCheckOutput(["/system/bin/logcat", "-d", "dalvikvm:S", "ConnectivityService:S", "WifiMonitor:S", "WifiStateTracker:S", "wpa_supplicant:S", "NetworkStateTracker:S"])
-            return output.split('\r')
-        except DMError, e:
-            # to preserve compat with parent method, just ignore exceptions
-            print "DeviceManager: Error recording logcat '%s'" % e.msg
-            pass
-
     def getInfo(self, directive=None):
         """
         Returns information about the device
 
         Directive indicates the information you want to get, your choices are:
           os - name of the os
           id - unique id of the device
           uptime - uptime of the device
@@ -757,17 +719,17 @@ class DeviceManagerADB(DeviceManager):
             # We are asserting that all commands will complete in this time unless otherwise specified
             timeout = self.default_timeout
 
         timeout = int(timeout)
         proc = subprocess.Popen(finalArgs)
         start_time = time.time()
         ret_code = proc.poll()
         while ((time.time() - start_time) <= timeout) and ret_code == None:
-            time.sleep(1)
+            time.sleep(self.pollingInterval)
             ret_code = proc.poll()
         if ret_code == None:
             proc.kill()
             raise DMError("Timeout exceeded for _checkCmd call")
         return ret_code
 
     def _checkCmdAs(self, args, timeout=None):
         """
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
@@ -13,17 +13,16 @@ import subprocess
 from threading import Thread
 import StringIO
 from devicemanager import DeviceManager, DMError, NetworkTools, _pop_last_line
 import errno
 from distutils.version import StrictVersion
 
 class DeviceManagerSUT(DeviceManager):
     debug = 2
-    tempRoot = os.getcwd()
     base_prompt = '$>'
     base_prompt_re = '\$\>'
     prompt_sep = '\x00'
     prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')'
     agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
     default_timeout = 300
 
     def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None, **kwargs):
@@ -636,23 +635,20 @@ class DeviceManagerSUT(DeviceManager):
         # read file data
         total_to_recv = filesize + len(prompt)
         buf = read_exact(total_to_recv, buf, 'could not get all file data')
         if buf[-len(prompt):] != prompt:
             err('no prompt found after file data--DeviceManager may be out of sync with agent')
             return buf
         return buf[:-len(prompt)]
 
-    def getFile(self, remoteFile, localFile = ''):
+    def getFile(self, remoteFile, localFile):
         """
         Copy file from device (remoteFile) to host (localFile)
         """
-        if localFile == '':
-            localFile = os.path.join(self.tempRoot, "temp.txt")
-
         data = self.pullFile(remoteFile)
 
         fhandle = open(localFile, 'wb')
         fhandle.write(data)
         fhandle.close()
         if not self.validateFile(remoteFile, localFile):
             raise DMError("Automation Error: Failed to validate file when downloading %s" %
                           remoteFile)
--- a/testing/mozbase/mozdevice/setup.py
+++ b/testing/mozbase/mozdevice/setup.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os
 from setuptools import setup
 
-PACKAGE_VERSION = '0.12'
+PACKAGE_VERSION = '0.14'
 
 # take description from README
 here = os.path.dirname(os.path.abspath(__file__))
 try:
     description = file(os.path.join(here, 'README.md')).read()
 except (OSError, IOError):
     description = ''