зеркало из https://github.com/mozilla/gecko-dev.git
Bug 797144 - mirror mozbase -> m-c for bug 796863 @ db7f115a9e
;r=wlach
This commit is contained in:
Родитель
2e7ac32196
Коммит
8debe5cabb
|
@ -0,0 +1,5 @@
|
|||
# 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/.
|
||||
|
||||
from b2gmixin import DeviceADB, DeviceSUT
|
|
@ -0,0 +1,171 @@
|
|||
# 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/.
|
||||
|
||||
from __future__ import with_statement
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import time
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
|
||||
from marionette import Marionette
|
||||
from mozdevice import DeviceManagerADB, DeviceManagerSUT, DMError
|
||||
|
||||
class B2GMixin(object):
|
||||
profileDir = None
|
||||
userJS = "/data/local/user.js"
|
||||
marionette = None
|
||||
|
||||
def __init__(self, host=None, marionette_port=2828, **kwargs):
|
||||
self.marionetteHost = host
|
||||
self.marionettePort = marionette_port
|
||||
|
||||
def cleanup(self):
|
||||
if self.profileDir:
|
||||
self.restoreProfile()
|
||||
|
||||
def waitForPort(self, timeout):
|
||||
"""
|
||||
Wait for the marionette server to respond.
|
||||
Timeout parameter is in seconds
|
||||
"""
|
||||
print "waiting for port"
|
||||
starttime = datetime.datetime.now()
|
||||
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
print "trying %s %s" % (self.marionettePort, self.marionetteHost)
|
||||
sock.connect((self.marionetteHost, self.marionettePort))
|
||||
data = sock.recv(16)
|
||||
sock.close()
|
||||
if '"from"' in data:
|
||||
return True
|
||||
except socket.error:
|
||||
pass
|
||||
except Exception as e:
|
||||
raise DMError("Could not connect to marionette: %s" % e)
|
||||
time.sleep(1)
|
||||
raise DMError("Could not communicate with Marionette port")
|
||||
|
||||
def setupMarionette(self):
|
||||
"""
|
||||
Start a marionette session.
|
||||
If no host is given, then this will get the ip
|
||||
of the device, and set up networking if needed.
|
||||
"""
|
||||
if not self.marionetteHost:
|
||||
self.setupDHCP()
|
||||
self.marionetteHost = self.getIP()
|
||||
if not self.marionette:
|
||||
self.marionette = Marionette(self.marionetteHost, self.marionettePort)
|
||||
if not self.marionette.session:
|
||||
self.waitForPort(30)
|
||||
self.marionette.start_session()
|
||||
|
||||
def restartB2G(self):
|
||||
"""
|
||||
Restarts the b2g process on the device
|
||||
"""
|
||||
#restart b2g so we start with a clean slate
|
||||
if self.marionette and self.marionette.session:
|
||||
self.marionette.delete_session()
|
||||
self.shellCheckOutput(['stop', 'b2g'])
|
||||
# Wait for a bit to make sure B2G has completely shut down.
|
||||
tries = 10
|
||||
while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0:
|
||||
tries -= 1
|
||||
time.sleep(1)
|
||||
if tries == 0:
|
||||
raise DMError("Could not kill b2g process")
|
||||
self.shellCheckOutput(['start', 'b2g'])
|
||||
|
||||
def setupProfile(self, prefs=None):
|
||||
"""
|
||||
Sets up the user profile on the device,
|
||||
The 'prefs' is a string of user_prefs to add to the profile.
|
||||
If it is not set, it will default to a standard b2g testing profile.
|
||||
"""
|
||||
if not prefs:
|
||||
prefs = """
|
||||
user_pref("power.screen.timeout", 999999);
|
||||
user_pref("devtools.debugger.force-local", false);
|
||||
"""
|
||||
#remove previous user.js if there is one
|
||||
if not self.profileDir:
|
||||
self.profileDir = tempfile.mkdtemp()
|
||||
our_userJS = os.path.join(self.profileDir, "user.js")
|
||||
if os.path.exists(our_userJS):
|
||||
os.remove(our_userJS)
|
||||
#copy profile
|
||||
try:
|
||||
output = self.getFile(self.userJS, our_userJS)
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
#if we successfully copied the profile, make a backup of the file
|
||||
if os.path.exists(our_userJS):
|
||||
self.shellCheckOutput(['dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS])
|
||||
with open(our_userJS, 'a') as user_file:
|
||||
user_file.write("%s" % prefs)
|
||||
self.pushFile(our_userJS, self.userJS)
|
||||
self.restartB2G()
|
||||
self.setupMarionette()
|
||||
|
||||
def setupDHCP(self, conn_type='eth0'):
|
||||
"""
|
||||
Sets up networking.
|
||||
|
||||
If conn_type is not set, it will assume eth0.
|
||||
"""
|
||||
tries = 5
|
||||
while tries > 0:
|
||||
print "attempts left: %d" % tries
|
||||
try:
|
||||
self.shellCheckOutput(['netcfg', conn_type, 'dhcp'], timeout=10)
|
||||
if self.getIP():
|
||||
return
|
||||
except DMError:
|
||||
pass
|
||||
tries = tries - 1
|
||||
raise DMError("Could not set up network connection")
|
||||
|
||||
def restoreProfile(self):
|
||||
"""
|
||||
Restores the original profile
|
||||
"""
|
||||
if not self.profileDir:
|
||||
raise DMError("There is no profile to restore")
|
||||
#if we successfully copied the profile, make a backup of the file
|
||||
our_userJS = os.path.join(self.profileDir, "user.js")
|
||||
if os.path.exists(our_userJS):
|
||||
self.shellCheckOutput(['dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS])
|
||||
shutil.rmtree(self.profileDir)
|
||||
self.profileDir = None
|
||||
|
||||
def getAppInfo(self):
|
||||
"""
|
||||
Returns the appinfo, with an additional "date" key.
|
||||
"""
|
||||
if not self.marionette or not self.marionette.session:
|
||||
self.setupMarionette()
|
||||
self.marionette.set_context("chrome")
|
||||
appinfo = self.marionette.execute_script("""
|
||||
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULAppInfo);
|
||||
return appInfo;
|
||||
""")
|
||||
(year, month, day) = (appinfo["appBuildID"][0:4], appinfo["appBuildID"][4:6], appinfo["appBuildID"][6:8])
|
||||
appinfo['date'] = "%s-%s-%s" % (year, month, day)
|
||||
return appinfo
|
||||
|
||||
class DeviceADB(DeviceManagerADB, B2GMixin):
|
||||
def __init__(self, **kwargs):
|
||||
DeviceManagerADB.__init__(self, **kwargs)
|
||||
B2GMixin.__init__(self, **kwargs)
|
||||
|
||||
class DeviceSUT(DeviceManagerSUT, B2GMixin):
|
||||
def __init__(self, **kwargs):
|
||||
DeviceManagerSUT.__init__(self, **kwargs)
|
||||
B2GMixin.__init__(self, **kwargs)
|
|
@ -0,0 +1,33 @@
|
|||
# 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.1'
|
||||
|
||||
# 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 = ''
|
||||
|
||||
deps = ['mozdevice', 'marionette_client']
|
||||
|
||||
setup(name='mozb2g',
|
||||
version=PACKAGE_VERSION,
|
||||
description="B2G specific code for device automation",
|
||||
long_description=description,
|
||||
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||
keywords='',
|
||||
author='Mozilla Automation and Testing Team',
|
||||
author_email='tools@lists.mozilla.org',
|
||||
url='https://wiki.mozilla.org/Auto-tools/Projects/MozBase',
|
||||
license='MPL',
|
||||
packages=['mozb2g'],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=deps
|
||||
)
|
|
@ -762,6 +762,35 @@ class DeviceManagerADB(DeviceManager):
|
|||
return None
|
||||
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:
|
||||
|
|
|
@ -290,7 +290,7 @@ falling back to not using job objects for managing child processes"""
|
|||
|
||||
if MOZPROCESS_DEBUG:
|
||||
print "DBG::MOZPROC Self.pid value is: %s" % self.pid
|
||||
|
||||
|
||||
while True:
|
||||
msgid = c_ulong(0)
|
||||
compkey = c_ulong(0)
|
||||
|
@ -311,8 +311,9 @@ falling back to not using job objects for managing child processes"""
|
|||
# don't want to mistake that situation for the situation of an unexpected
|
||||
# parent abort (which is what we're looking for here).
|
||||
if diff.seconds > self.MAX_IOCOMPLETION_PORT_NOTIFICATION_DELAY:
|
||||
print >> sys.stderr, "Parent process exited without \
|
||||
killing children, attempting to kill children"
|
||||
print >> sys.stderr, "Parent process %s exited with children alive:" % self.pid
|
||||
print >> sys.stderr, "PIDS: %s" % ', '.join(self._spawned_procs.keys())
|
||||
print >> sys.stderr, "Attempting to kill them..."
|
||||
self.kill()
|
||||
self._process_events.put({self.pid: 'FINISHED'})
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче