Bug 785273 - Prevent circular references to Marionette instances, r=mdas
authorJonathan Griffin <jgriffin@mozilla.com>
Thu, 23 Aug 2012 17:31:42 -0700
changeset 103321 3c0b16397ce910ca3e04ba058d4621d2609a5b80
parent 103320 e5259919146b1cc402ad9f4b20217d612af91037
child 103322 5870ef9c6afacc38175f767a0989c301cc8f3445
push id23343
push userryanvm@gmail.com
push dateSat, 25 Aug 2012 02:53:35 +0000
treeherdermozilla-central@f077de66e52d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmdas
bugs785273
milestone17.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 785273 - Prevent circular references to Marionette instances, r=mdas
testing/marionette/client/marionette/marionette_test.py
testing/marionette/client/marionette/runtests.py
--- a/testing/marionette/client/marionette/marionette_test.py
+++ b/testing/marionette/client/marionette/marionette_test.py
@@ -68,29 +68,36 @@ let [url, permissions] = arguments;
 let uri = Services.io.newURI(url, null, null);
 permissions.forEach(function (perm) {
     Services.perms.add(uri, "sms", Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
 });
         """, [url, permissions])
         emulator.set_context("content")
 
     def setUp(self):
+        # Convert the marionette weakref to an object, just for the
+        # duration of the test; this is deleted in tearDown() to prevent
+        # a persistent circular reference which in turn would prevent
+        # proper garbage collection.
+        self.marionette = self._marionette_weakref()
         if self.marionette.session is None:
             self.marionette.start_session()
 
     def tearDown(self):
         if self.marionette.session is not None:
             self.loglines = self.marionette.get_logs()
             self.perfdata = self.marionette.get_perf_data()
             self.marionette.delete_session()
+        self.marionette = None
 
 class MarionetteTestCase(CommonTestCase):
 
-    def __init__(self, marionette, methodName='runTest', **kwargs):
-        self.marionette = marionette
+    def __init__(self, marionette_weakref, methodName='runTest', **kwargs):
+        self._marionette_weakref = marionette_weakref
+        self.marionette = None
         self.extra_emulator_index = -1
         CommonTestCase.__init__(self, methodName, **kwargs)
 
     def get_new_emulator(self):
         self.extra_emulator_index += 1
         if len(self.marionette.extra_emulators) == self.extra_emulator_index:
             qemu  = Marionette(emulator=self.marionette.emulator.arch,
                                emulatorBinary=self.marionette.emulator.binary,
--- a/testing/marionette/client/marionette/runtests.py
+++ b/testing/marionette/client/marionette/runtests.py
@@ -9,16 +9,17 @@ import logging
 from optparse import OptionParser
 import os
 import types
 import unittest
 import socket
 import sys
 import time
 import platform
+import weakref
 import xml.dom.minidom as dom
 
 try:
     from manifestparser import TestManifest
     from mozhttpd import iface, MozHttpd
 except ImportError:
     print "manifestparser or mozhttpd not found!  Please install mozbase:\n"
     print "\tgit clone git://github.com/mozilla/mozbase.git"
@@ -304,23 +305,16 @@ class MarionetteTestRunner(object):
         if self.autolog:
             self.post_to_autolog(self.elapsedtime)
         if self.perfrequest and options.perf:
             try:
                 self.perfrequest.submit()
             except Exception, e:
                 print "Could not submit to datazilla"
                 print e
-        if self.marionette.emulator:
-            self.marionette.emulator.close()
-            self.marionette.emulator = None
-        if self.marionette.instance:
-            self.marionette.instance.close()
-            self.marionette.instance = None
-        self.marionette = None
 
         if self.xml_output:
             with open(self.xml_output, 'w') as f:
                 f.write(self.generate_xml(self.results))
 
     def run_test(self, test, testtype):
         if not self.httpd:
             print "starting httpd"
@@ -396,20 +390,20 @@ class MarionetteTestRunner(object):
             test_mod = imp.load_source(mod_name, filepath)
 
             for name in dir(test_mod):
                 obj = getattr(test_mod, name)
                 if (isinstance(obj, (type, types.ClassType)) and
                     issubclass(obj, unittest.TestCase)):
                     testnames = testloader.getTestCaseNames(obj)
                     for testname in testnames:
-                        suite.addTest(obj(self.marionette, methodName=testname))
+                        suite.addTest(obj(weakref.ref(self.marionette), methodName=testname))
 
         elif file_ext == '.js':
-            suite.addTest(MarionetteJSTestCase(self.marionette, jsFile=filepath))
+            suite.addTest(MarionetteJSTestCase(weakref.ref(self.marionette), jsFile=filepath))
 
         if suite.countTestCases():
             results = MarionetteTextTestRunner(verbosity=3).run(suite)
             self.results.append(results)
 
             self.failed += len(results.failures) + len(results.errors)
             if results.perfdata and options.perf:
                 self.perfrequest.add_datazilla_result(results.perfdata)