Bug 785273 - Prevent circular references to Marionette instances, r=mdas
authorJonathan Griffin <jgriffin@mozilla.com>
Thu, 23 Aug 2012 17:31:42 -0700
changeset 105354 3c0b16397ce910ca3e04ba058d4621d2609a5b80
parent 105353 e5259919146b1cc402ad9f4b20217d612af91037
child 105355 5870ef9c6afacc38175f767a0989c301cc8f3445
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersmdas
bugs785273
milestone17.0a1
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)