Bug 808719 - Mirror over mozdevice 0.14;r=jmaher
authorWilliam Lachance <wlachance@mozilla.com>
Mon, 05 Nov 2012 15:18:54 -0800
changeset 120293 613bfe02f0c1096027e73238a9fcc27ee480531e
parent 120292 4cee05d5b1ce84770ad35222f7962289c323304f
child 120294 c697c428739d1014d81e7e8b0afe8b28f5a08642
push idunknown
push userunknown
push dateunknown
reviewersjmaher
bugs808719
milestone19.0a1
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 = ''