blob: b17a320e91ffc2e124b5a4bd4c01fc8524b8069b [file] [log] [blame]
# 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)