From 82336471686dd5ec2b866d746ac1b981af9cdec3 Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Thu, 27 Sep 2012 12:31:49 +0100 Subject: [PATCH 1/8] Bug 793947 - Race condition in dbg-server.js breaks Marionette; r=msucan --- .../devtools/debugger/server/dbg-server.js | 4 +-- .../debugger/tests/unit/test_dbgsocket.js | 31 ++----------------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/toolkit/devtools/debugger/server/dbg-server.js b/toolkit/devtools/debugger/server/dbg-server.js index abded85f443d..12370ef66f8f 100644 --- a/toolkit/devtools/debugger/server/dbg-server.js +++ b/toolkit/devtools/debugger/server/dbg-server.js @@ -316,12 +316,10 @@ var DebuggerServer = { }, /** - * Remove the connection from the debugging server and shut down the server - * if no other connections are open. + * Remove the connection from the debugging server. */ _connectionClosed: function DH_connectionClosed(aConnection) { delete this._connections[aConnection.prefix]; - this.destroy(); } }; diff --git a/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js b/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js index f19c57ad6e87..516625efb900 100644 --- a/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js +++ b/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js @@ -59,35 +59,10 @@ function test_socket_conn() function test_socket_shutdown() { - let count = 0; - wait_for_server_shutdown(count); -} - -function wait_for_server_shutdown(aCount) -{ - do_timeout(100, function() { - dump("count: "+aCount+" "); - if (++aCount > 20) { - do_throw("Timed out waiting for the server to shut down."); - return; - } - if (DebuggerServer.initialized) { - wait_for_server_shutdown(aCount); - return; - } - real_test_socket_shutdown(aCount); - }); -} - -function real_test_socket_shutdown() -{ - // After the last conection was closed, the server must be initialized again. - // Allow incoming connections. - DebuggerServer.init(function () true); - DebuggerServer.addActors("resource://test/testactors.js"); - + do_check_eq(DebuggerServer._socketConnections, 1); + do_check_true(DebuggerServer.closeListener()); do_check_eq(DebuggerServer._socketConnections, 0); - // Make sure closing a non-started listener does nothing. + // Make sure closing the listener twice does nothing. do_check_false(DebuggerServer.closeListener()); do_check_eq(DebuggerServer._socketConnections, 0); From 6a5b33a1f69d15fcc2932923d1e4a681be2e371e Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Thu, 27 Sep 2012 16:28:01 +0100 Subject: [PATCH 2/8] Bug 786301 - 1/3 - Add RemoveAllForApp on nsDOMStorageDBWrapper and nsDOMStoragePersistentDB. r=honza --- dom/src/storage/nsDOMStorageDBWrapper.cpp | 9 ++++++ dom/src/storage/nsDOMStorageDBWrapper.h | 9 ++++++ dom/src/storage/nsDOMStoragePersistentDB.cpp | 33 ++++++++++++++++++++ dom/src/storage/nsDOMStoragePersistentDB.h | 9 ++++++ 4 files changed, 60 insertions(+) diff --git a/dom/src/storage/nsDOMStorageDBWrapper.cpp b/dom/src/storage/nsDOMStorageDBWrapper.cpp index 764f6dd0efa1..33eda4e86600 100644 --- a/dom/src/storage/nsDOMStorageDBWrapper.cpp +++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp @@ -202,6 +202,15 @@ nsDOMStorageDBWrapper::RemoveAll() return rv; } +nsresult +nsDOMStorageDBWrapper::RemoveAllForApp(uint32_t aAppId, bool aOnlyBrowserElement) +{ + // We only care about removing the permament storage. Temporary storage such + // as session storage or private browsing storage will not be re-used anyway + // and will be automatically deleted at some point. + return mPersistentDB.RemoveAllForApp(aAppId, aOnlyBrowserElement); +} + nsresult nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage) { diff --git a/dom/src/storage/nsDOMStorageDBWrapper.h b/dom/src/storage/nsDOMStorageDBWrapper.h index a20ea18d632e..519699e7fdcf 100644 --- a/dom/src/storage/nsDOMStorageDBWrapper.h +++ b/dom/src/storage/nsDOMStorageDBWrapper.h @@ -137,6 +137,15 @@ public: nsresult RemoveAll(); + /** + * Removes all keys from storage for a specific app. + * If aOnlyBrowserElement is true, it will remove only keys with the + * browserElement flag set. + * aAppId has to be a valid app id. It can't be NO_APP_ID or UNKNOWN_APP_ID. + */ + nsresult + RemoveAllForApp(uint32_t aAppId, bool aOnlyBrowserElement); + /** * Returns usage for a storage using its GetQuotaDBKey() as a key. */ diff --git a/dom/src/storage/nsDOMStoragePersistentDB.cpp b/dom/src/storage/nsDOMStoragePersistentDB.cpp index 2e8d4fe849bb..e6041ed1ed0e 100644 --- a/dom/src/storage/nsDOMStoragePersistentDB.cpp +++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp @@ -664,6 +664,39 @@ nsDOMStoragePersistentDB::RemoveAll() return NS_OK; } +nsresult +nsDOMStoragePersistentDB::RemoveAllForApp(uint32_t aAppId, bool aOnlyBrowserElement) +{ + nsresult rv; + + rv = MaybeCommitInsertTransaction(); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr stmt = mStatements.GetCachedStatement( + "DELETE FROM webappsstore2_view " + "WHERE scope LIKE :scope" + ); + NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scopeStmt(stmt); + + nsAutoCString scope; + scope.AppendInt(aAppId); + if (aOnlyBrowserElement) { + scope.Append(NS_LITERAL_CSTRING(":t:%")); + } else { + scope.Append(NS_LITERAL_CSTRING(":_:%")); + } + rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"), scope); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + MarkAllScopesDirty(); + + return NS_OK; +} + nsresult nsDOMStoragePersistentDB::GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage) diff --git a/dom/src/storage/nsDOMStoragePersistentDB.h b/dom/src/storage/nsDOMStoragePersistentDB.h index 72d7f691d384..5519adb1d184 100644 --- a/dom/src/storage/nsDOMStoragePersistentDB.h +++ b/dom/src/storage/nsDOMStoragePersistentDB.h @@ -98,6 +98,15 @@ public: nsresult RemoveAll(); + /** + * Removes all keys from storage for a specific app. + * If aOnlyBrowserElement is true, it will remove only keys with the + * browserElement flag set. + * aAppId has to be a valid app id. It can't be NO_APP_ID or UNKNOWN_APP_ID. + */ + nsresult + RemoveAllForApp(uint32_t aAppId, bool aOnlyBrowserElement); + /** * Returns usage for a storage using its GetQuotaDBKey() as a key. */ From 101a567876b1a305bd62678c40e9a0ecb9ce2c9a Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Thu, 27 Sep 2012 16:28:44 +0100 Subject: [PATCH 3/8] Bug 786301 - 2/3 - Remove localStorage data from an app when uninstalled. r=jlebar --- dom/src/storage/nsDOMStorage.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp index 7b02ec0bb2f0..a15ae7721147 100644 --- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -37,6 +37,8 @@ using mozilla::dom::ContentChild; #include "mozilla/Telemetry.h" #include "DictionaryHelpers.h" #include "GeneratedEvents.h" +#include "nsIAppsService.h" +#include "mozIApplication.h" // calls FlushAndDeleteTemporaryTables(false) #define NS_DOMSTORAGE_FLUSH_TIMER_TOPIC "domstorage-flush-timer" @@ -162,6 +164,8 @@ nsDOMStorageManager::Initialize() NS_ENSURE_SUCCESS(rv, rv); rv = os->AddObserver(gStorageManager, "last-pb-context-exited", true); NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, "webapps-uninstall", true); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -307,6 +311,23 @@ nsDOMStorageManager::Observe(nsISupports *aSubject, if (DOMStorageImpl::gStorageDB) { return DOMStorageImpl::gStorageDB->DropPrivateBrowsingStorages(); } + } else if (!strcmp(aTopic, "webapps-uninstall")) { + if (!DOMStorageImpl::gStorageDB) { + return NS_OK; + } + + nsCOMPtr appsService = do_GetService("@mozilla.org/AppsService;1"); + nsCOMPtr app; + + appsService->GetAppFromObserverMessage(nsAutoString(aData), getter_AddRefs(app)); + NS_ENSURE_TRUE(app, NS_ERROR_UNEXPECTED); + + uint32_t appId; + app->GetLocalId(&appId); + MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID); + + return DOMStorageImpl::gStorageDB->RemoveAllForApp(appId, + /* onlyBrowserElements */ false); } return NS_OK; From ceae2a07010195190512f83dd20b76368563df0e Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Thu, 27 Sep 2012 16:29:25 +0100 Subject: [PATCH 4/8] Bug 786301 - 3/3 - Test that localStorage is removed when an app is uninstalled. r=honza --- dom/tests/mochitest/localstorage/Makefile.in | 1 + .../localstorage/test_app_uninstall.html | 236 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 dom/tests/mochitest/localstorage/test_app_uninstall.html diff --git a/dom/tests/mochitest/localstorage/Makefile.in b/dom/tests/mochitest/localstorage/Makefile.in index 2a6b63b222ee..bc83b78f282a 100644 --- a/dom/tests/mochitest/localstorage/Makefile.in +++ b/dom/tests/mochitest/localstorage/Makefile.in @@ -59,6 +59,7 @@ MOCHITEST_FILES = \ MOCHITEST_CHROME_FILES = \ test_localStorageFromChrome.xhtml \ + test_app_uninstall.html \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/tests/mochitest/localstorage/test_app_uninstall.html b/dom/tests/mochitest/localstorage/test_app_uninstall.html new file mode 100644 index 000000000000..faa2939540c0 --- /dev/null +++ b/dom/tests/mochitest/localstorage/test_app_uninstall.html @@ -0,0 +1,236 @@ + + + + + + Tests that uninstalling app removes the localStorage data + + + + +Mozilla Bug 786301 +

+
+ +
+
+
+
+ + From 77826d02c6afce0d793445dff7b4f81d17f37df1 Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Thu, 27 Sep 2012 08:59:31 -0700 Subject: [PATCH 5/8] Bug 794973 - 'Make mozIApplicationClearPrivateDataParams inherit nsISupports'. r=khuey. --- dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl b/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl index 16d86e613ad8..06b8e5b96c27 100644 --- a/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl +++ b/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl @@ -8,7 +8,7 @@ #include "nsISupports.idl" [scriptable, uuid(ba0e6c8e-8c03-4b9b-8f9b-4fb14216f56e)] -interface mozIApplicationClearPrivateDataParams +interface mozIApplicationClearPrivateDataParams : nsISupports { readonly attribute unsigned long appId; readonly attribute boolean browserOnly; From 2b947c3c7f11139f3e3dc467da76dfb98ed6ff56 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Thu, 27 Sep 2012 10:12:48 -0700 Subject: [PATCH 6/8] Bug 794729 - Run config.guess and mozconfig through shell; r=glandium DONTBUILD (NPOTB) --- python/mozbuild/mozbuild/base.py | 58 +++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/python/mozbuild/mozbuild/base.py b/python/mozbuild/mozbuild/base.py index 1b2c934263f1..268bd830888f 100644 --- a/python/mozbuild/mozbuild/base.py +++ b/python/mozbuild/mozbuild/base.py @@ -103,14 +103,20 @@ class MozbuildObject(object): # files are tightly coupled with the environment by definition. In the # future, perhaps we'll have a more sanitized environment for mozconfig # execution. + # + # The force of str is required because subprocess on Python <2.7.3 + # does not like unicode in environment keys or values. At the time this + # was written, Mozilla shipped Python 2.7.2 with MozillaBuild. env = dict(os.environ) if path is not None: - env['MOZCONFIG'] = path + env[str('MOZCONFIG')] = path - env['CONFIG_GUESS'] = self._config_guess + env[str('CONFIG_GUESS')] = self._config_guess - output = subprocess.check_output([loader, self.topsrcdir], - stderr=subprocess.PIPE, cwd=self.topsrcdir, env=env) + args = self._normalize_command([loader, self.topsrcdir], True) + + output = subprocess.check_output(args, stderr=subprocess.PIPE, + cwd=self.topsrcdir, env=env) # The output is make syntax. We parse this in a specialized make # context. @@ -147,7 +153,8 @@ class MozbuildObject(object): if self._config_guess_output is None: p = os.path.join(self.topsrcdir, 'build', 'autoconf', 'config.guess') - self._config_guess_output = subprocess.check_output([p], + args = self._normalize_command([p], True) + self._config_guess_output = subprocess.check_output(args, cwd=self.topsrcdir).strip() return self._config_guess_output @@ -292,20 +299,7 @@ class MozbuildObject(object): within a UNIX environment. Basically, if we are on Windows, it will execute the command via an appropriate UNIX-like shell. """ - assert isinstance(args, list) and len(args) - - if require_unix_environment and _in_msys: - # Always munge Windows-style into Unix style for the command. - prog = args[0].replace('\\', '/') - - # PyMake removes the C: prefix. But, things seem to work here - # without it. Not sure what that's about. - - # We run everything through the msys shell. We need to use - # '-c' and pass all the arguments as one argument because that is - # how sh works. - cline = subprocess.list2cmdline([prog] + args[1:]) - args = [_current_shell, '-c', cline] + args = self._normalize_command(args, require_unix_environment) self.log(logging.INFO, 'process', {'args': args}, ' '.join(args)) @@ -336,6 +330,32 @@ class MozbuildObject(object): if status != 0 and not ignore_errors: raise Exception('Process executed with non-0 exit code: %s' % args) + def _normalize_command(self, args, require_unix_environment): + """Adjust command arguments to run in the necessary environment. + + This exists mainly to facilitate execution of programs requiring a *NIX + shell when running on Windows. The caller specifies whether a shell + environment is required. If it is and we are running on Windows but + aren't running in the UNIX-like msys environment, then we rewrite the + command to execute via a shell. + """ + assert isinstance(args, list) and len(args) + + if not require_unix_environment or not _in_msys: + return args + + # Always munge Windows-style into Unix style for the command. + prog = args[0].replace('\\', '/') + + # PyMake removes the C: prefix. But, things seem to work here + # without it. Not sure what that's about. + + # We run everything through the msys shell. We need to use + # '-c' and pass all the arguments as one argument because that is + # how sh works. + cline = subprocess.list2cmdline([prog] + args[1:]) + return [_current_shell, '-c', cline] + def _is_windows(self): return os.name in ('nt', 'ce') From fc58561b1a594c79d710cf30093e3d27218646d7 Mon Sep 17 00:00:00 2001 From: Jonathan Griffin Date: Thu, 27 Sep 2012 10:42:37 -0700 Subject: [PATCH 7/8] Bug 794692 - Change Marionette's package name to marionette_client, r=mdas, DONTBUILD (NPOTB) --- testing/marionette/client/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/marionette/client/setup.py b/testing/marionette/client/setup.py index c708056dd8f0..7c02adc19966 100644 --- a/testing/marionette/client/setup.py +++ b/testing/marionette/client/setup.py @@ -14,7 +14,7 @@ except (OSError, IOError): deps = ['manifestdestiny', 'mozhttpd >= 0.3', 'mozprocess == 0.5', 'mozrunner == 5.10'] -setup(name='marionette', +setup(name='marionette_client', version=version, description="Marionette test automation client", long_description=description, From bc1d385b46aa619097ba38e738fc416b9e02ebf7 Mon Sep 17 00:00:00 2001 From: Jonathan Griffin Date: Thu, 27 Sep 2012 13:47:17 -0700 Subject: [PATCH 8/8] Bug 789976 - Add --gecko-path argument to Marionette, r=ahal, DONTBUILD (NPOTB) --- .../marionette/client/marionette/emulator.py | 82 ++++++++++++------- .../client/marionette/marionette.py | 17 ++-- .../client/marionette/marionette_test.py | 3 +- .../marionette/client/marionette/runtests.py | 19 +++-- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/testing/marionette/client/marionette/emulator.py b/testing/marionette/client/marionette/emulator.py index e6a8a592fbb1..b662f8a7eb38 100644 --- a/testing/marionette/client/marionette/emulator.py +++ b/testing/marionette/client/marionette/emulator.py @@ -36,8 +36,9 @@ class Emulator(object): deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$") - def __init__(self, homedir=None, noWindow=False, logcat_dir=None, arch="x86", - emulatorBinary=None, res='480x800', sdcard=None, userdata=None): + def __init__(self, homedir=None, noWindow=False, logcat_dir=None, + arch="x86", emulatorBinary=None, res='480x800', sdcard=None, + userdata=None, gecko_path=None): self.port = None self._emulator_launched = False self.proc = None @@ -59,6 +60,7 @@ class Emulator(object): self.homedir = os.path.expanduser(homedir) self.dataImg = userdata self.copy_userdata = self.dataImg is None + self.gecko_path = gecko_path def _check_for_b2g(self): if self.homedir is None: @@ -67,7 +69,7 @@ class Emulator(object): raise Exception('Must define B2G_HOME or pass the homedir parameter') self._check_file(self.homedir) - oldstyle_homedir = os.path.join(self.homedir, 'glue','gonk-ics') + oldstyle_homedir = os.path.join(self.homedir, 'glue', 'gonk-ics') if os.access(oldstyle_homedir, os.F_OK): self.homedir = oldstyle_homedir @@ -79,7 +81,7 @@ class Emulator(object): if platform.system() == "Darwin": host_dir = "darwin-x86" - host_bin_dir = os.path.join("out","host", host_dir, "bin") + host_bin_dir = os.path.join("out", "host", host_dir, "bin") if self.arch == "x86": binary = os.path.join(host_bin_dir, "emulator-x86") @@ -125,10 +127,10 @@ class Emulator(object): @property def args(self): - qemuArgs = [ self.binary, - '-kernel', self.kernelImg, - '-sysdir', self.sysDir, - '-data', self.dataImg ] + qemuArgs = [self.binary, + '-kernel', self.kernelImg, + '-sysdir', self.sysDir, + '-data', self.dataImg] if self._tmp_sdcard: qemuArgs.extend(['-sdcard', self._tmp_sdcard]) if self.noWindow: @@ -147,16 +149,16 @@ class Emulator(object): return self.proc is not None and self.proc.poll() is None else: return self.port is not None - + def create_sdcard(self, sdcard): - self._tmp_sdcard = tempfile.mktemp(prefix='sdcard') - sdargs = [self.mksdcard, "-l" , "mySdCard", sdcard, self._tmp_sdcard] - sd = subprocess.Popen(sdargs, stdout= subprocess.PIPE, stderr=subprocess.STDOUT) - retcode = sd.wait() - if retcode: - raise Exception('unable to create sdcard : exit code %d: %s' - % (retcode, adb.stdout.read())) - return None + self._tmp_sdcard = tempfile.mktemp(prefix='sdcard') + sdargs = [self.mksdcard, "-l", "mySdCard", sdcard, self._tmp_sdcard] + sd = subprocess.Popen(sdargs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + retcode = sd.wait() + if retcode: + raise Exception('unable to create sdcard : exit code %d: %s' + % (retcode, sd.stdout.read())) + return None def _check_for_adb(self): host_dir = "linux-x86" @@ -166,12 +168,13 @@ class Emulator(object): stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if adb.wait() == 0: - self.adb = adb.stdout.read().strip() # remove trailing newline + self.adb = adb.stdout.read().strip() # remove trailing newline return - adb_paths = [os.path.join(self.homedir,'glue','gonk','out','host', - host_dir ,'bin','adb'),os.path.join(self.homedir, 'out', - 'host', host_dir,'bin', 'adb'),os.path.join(self.homedir, - 'bin','adb')] + adb_paths = [os.path.join(self.homedir, 'glue', 'gonk', 'out', 'host', + host_dir, 'bin', 'adb'), + os.path.join(self.homedir, 'out', 'host', host_dir, + 'bin', 'adb'), + os.path.join(self.homedir, 'bin', 'adb')] for option in adb_paths: if os.path.exists(option): self.adb = option @@ -180,10 +183,13 @@ class Emulator(object): def _run_adb(self, args): args.insert(0, self.adb) + if self.port: + args.insert(1, '-s') + args.insert(2, 'emulator-%d' % self.port) adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) retcode = adb.wait() if retcode: - raise Exception('adb terminated with exit code %d: %s' + raise Exception('adb terminated with exit code %d: %s' % (retcode, adb.stdout.read())) return adb.stdout.read() @@ -198,7 +204,7 @@ class Emulator(object): if line.startswith('OK'): return output elif line.startswith('KO:'): - raise Exception ('bad telnet response: %s' % line) + raise Exception('bad telnet response: %s' % line) def _run_telnet(self, command): if not self.telnet: @@ -219,7 +225,7 @@ class Emulator(object): if self._tmp_userdata: os.remove(self._tmp_userdata) self._tmp_userdata = None - if self._tmp_sdcard: + if self._tmp_sdcard: os.remove(self._tmp_sdcard) self._tmp_sdcard = None return retcode @@ -269,6 +275,8 @@ class Emulator(object): online, offline = self._get_adb_devices() self.port = int(list(online)[0]) + self.install_gecko() + def start(self): self._check_for_b2g() self.start_adb() @@ -301,8 +309,9 @@ class Emulator(object): self.save_logcat() # setup DNS fix for networking - self._run_adb(['-s', 'emulator-%d' % self.port, - 'shell', 'setprop', 'net.dns1', '10.0.2.3']) + self._run_adb(['shell', 'setprop', 'net.dns1', '10.0.2.3']) + + self.install_gecko() def _save_logcat_proc(self, filename, cmd): self.logcat_proc = LogcatProc(filename, cmd) @@ -311,6 +320,21 @@ class Emulator(object): self.logcat_proc.waitForFinish() self.logcat_proc = None + def install_gecko(self): + """ + Install gecko into the emulator using adb push. Restart b2g after the + installation. + """ + if not self.gecko_path: + return + # need to remount so we can write to /system/b2g + self._run_adb(['remount']) + self._run_adb(['shell', 'stop', 'b2g']) + print 'installing gecko binaries' + self._run_adb(['push', self.gecko_path, '/system/b2g']) + print 'restarting B2G' + self._run_adb(['shell', 'start', 'b2g']) + def rotate_log(self, srclog, index=1): """ Rotate a logfile, by recursively rotating logs further in the sequence, deleting the last file if necessary. @@ -349,8 +373,7 @@ class Emulator(object): local_port = s.getsockname()[1] s.close() - output = self._run_adb(['-s', 'emulator-%d' % self.port, - 'forward', + output = self._run_adb(['forward', 'tcp:%d' % local_port, 'tcp:%d' % remote_port]) @@ -374,4 +397,3 @@ class Emulator(object): print traceback.format_exc() time.sleep(1) return False - diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index d66084fc1d27..d34fac0da20f 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -85,9 +85,10 @@ class Marionette(object): CONTEXT_CONTENT = 'content' def __init__(self, host='localhost', port=2828, bin=None, profile=None, - emulator=None, sdcard= None, emulatorBinary=None, emulatorImg=None, - emulator_res='480x800', connectToRunningEmulator=False, - homedir=None, baseurl=None, noWindow=False, logcat_dir=None): + emulator=None, sdcard=None, emulatorBinary=None, + emulatorImg=None, emulator_res='480x800', gecko_path=None, + connectToRunningEmulator=False, homedir=None, baseurl=None, + noWindow=False, logcat_dir=None): self.host = host self.port = self.local_port = port self.bin = bin @@ -101,6 +102,7 @@ class Marionette(object): self.baseurl = baseurl self.noWindow = noWindow self.logcat_dir = logcat_dir + self.gecko_path = gecko_path if bin: self.instance = GeckoInstance(host=self.host, port=self.port, @@ -115,13 +117,16 @@ class Marionette(object): sdcard=sdcard, emulatorBinary=emulatorBinary, userdata=emulatorImg, - res=emulator_res) + res=emulator_res, + gecko_path=self.gecko_path) self.emulator.start() self.port = self.emulator.setup_port_forwarding(self.port) assert(self.emulator.wait_for_port()) if connectToRunningEmulator: - self.emulator = Emulator(homedir=homedir, logcat_dir=self.logcat_dir) + self.emulator = Emulator(homedir=homedir, + logcat_dir=self.logcat_dir, + gecko_path=self.gecko_path) self.emulator.connect() self.port = self.emulator.setup_port_forwarding(self.port) assert(self.emulator.wait_for_port()) @@ -262,7 +267,7 @@ class Marionette(object): def current_window_handle(self): self.window = self._send_message('getWindow', 'value') return self.window - + @property def title(self): response = self._send_message('getTitle', 'value') diff --git a/testing/marionette/client/marionette/marionette_test.py b/testing/marionette/client/marionette/marionette_test.py index d632ce58dd1d..bdc07a84fb95 100644 --- a/testing/marionette/client/marionette/marionette_test.py +++ b/testing/marionette/client/marionette/marionette_test.py @@ -129,7 +129,8 @@ class MarionetteTestCase(CommonTestCase): emulatorBinary=self.marionette.emulator.binary, homedir=self.marionette.homedir, baseurl=self.marionette.baseurl, - noWindow=self.marionette.noWindow) + noWindow=self.marionette.noWindow, + gecko_path=self.marionette.gecko_path) qemu.start_session() self.marionette.extra_emulators.append(qemu) else: diff --git a/testing/marionette/client/marionette/runtests.py b/testing/marionette/client/marionette/runtests.py index 5b5dde1c9c47..c68d335d9209 100644 --- a/testing/marionette/client/marionette/runtests.py +++ b/testing/marionette/client/marionette/runtests.py @@ -171,7 +171,8 @@ class MarionetteTestRunner(object): bin=None, profile=None, autolog=False, revision=None, es_server=None, rest_server=None, logger=None, testgroup="marionette", noWindow=False, logcat_dir=None, - xml_output=None, repeat=0, perf=False, perfserv=None): + xml_output=None, repeat=0, perf=False, perfserv=None, + gecko_path=None): self.address = address self.emulator = emulator self.emulatorBinary = emulatorBinary @@ -196,6 +197,7 @@ class MarionetteTestRunner(object): self.repeat = repeat self.perf = perf self.perfserv = perfserv + self.gecko_path = gecko_path # set up test handlers self.test_handlers = [] @@ -253,7 +255,8 @@ class MarionetteTestRunner(object): connectToRunningEmulator=True, homedir=self.homedir, baseurl=self.baseurl, - logcat_dir=self.logcat_dir) + logcat_dir=self.logcat_dir, + gecko_path=self.gecko_path) else: self.marionette = Marionette(host=host, port=int(port), @@ -266,7 +269,8 @@ class MarionetteTestRunner(object): homedir=self.homedir, baseurl=self.baseurl, noWindow=self.noWindow, - logcat_dir=self.logcat_dir) + logcat_dir=self.logcat_dir, + gecko_path=self.gecko_path) else: raise Exception("must specify binary, address or emulator") @@ -604,7 +608,11 @@ def parse_options(): default=0, help='number of times to repeat the test(s).') parser.add_option('-x', '--xml-output', action='store', dest='xml_output', help='XML output.') - + parser.add_option('--gecko-path', dest='gecko_path', action='store', + default=None, + help='path to B2G gecko binaries that should be ' + 'installed on the device or emulator') + options, tests = parser.parse_args() if not tests: @@ -653,7 +661,8 @@ def startTestRunner(runner_class, options, tests): xml_output=options.xml_output, repeat=options.repeat, perf=options.perf, - perfserv=options.perfserv) + perfserv=options.perfserv, + gecko_path=options.gecko_path) runner.run_tests(tests, testtype=options.type) return runner