Bug 1309318 - Make the httpd server available to TestCase class to allow custom handlers.
MozReview-Commit-ID: HpazIlQG1Yq
--- a/testing/marionette/harness/marionette/marionette_test/testcases.py
+++ b/testing/marionette/harness/marionette/marionette_test/testcases.py
@@ -220,17 +220,18 @@ class CommonTestCase(unittest.TestCase):
This is done by looking for a match for the filename using cls.match_re.
"""
if not cls.match_re:
return False
m = cls.match_re.match(filename)
return m is not None
@classmethod
- def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars):
+ def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
+ httpd, testvars):
"""Add all the tests in the specified file to the specified suite."""
raise NotImplementedError
@property
def test_name(self):
if hasattr(self, 'jsFile'):
return os.path.basename(self.jsFile)
else:
@@ -247,16 +248,17 @@ class CommonTestCase(unittest.TestCase):
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.start_time = time.time()
self.marionette = self._marionette_weakref()
+ self.httpd = self._httpd_weakref()
if self.marionette.session is None:
self.marionette.start_session()
self.marionette.reset_timeouts()
super(CommonTestCase, self).setUp()
def cleanTest(self):
self._deleteSession()
@@ -419,29 +421,31 @@ if (!testUtils.hasOwnProperty("specialPo
raise
self.marionette.test_name = original_test_name
class MarionetteTestCase(CommonTestCase):
match_re = re.compile(r"test_(.*)\.py$")
- def __init__(self, marionette_weakref, methodName='runTest',
+ def __init__(self, marionette_weakref, httpd_weakref, methodName='runTest',
filepath='', **kwargs):
self._marionette_weakref = marionette_weakref
- self.marionette = None
+ self._httpd_weakref = httpd_weakref
self.methodName = methodName
self.filepath = filepath
self.testvars = kwargs.pop('testvars', None)
+ self.marionette = None
+
super(MarionetteTestCase, self).__init__(methodName, **kwargs)
@classmethod
def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
- testvars, **kwargs):
+ httpd, testvars, **kwargs):
# since we use imp.load_source to load test modules, if a module
# is loaded with the same name as another one the module would just be
# reloaded.
#
# We may end up by finding too many test in a module then since
# reload() only update the module dict (so old keys are still there!)
# see https://docs.python.org/2/library/functions.html#reload
#
@@ -455,20 +459,21 @@ class MarionetteTestCase(CommonTestCase)
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(weakref.ref(marionette),
- methodName=testname,
- filepath=filepath,
- testvars=testvars,
- **kwargs))
+ weakref.ref(httpd),
+ methodName=testname,
+ filepath=filepath,
+ testvars=testvars,
+ **kwargs))
def setUp(self):
super(MarionetteTestCase, self).setUp()
self.marionette.test_name = self.test_name
self.marionette.execute_script("log('TEST-START: {0}:{1}')"
.format(self.filepath.replace('\\', '\\\\'),
self.methodName),
sandbox="simpletest")
@@ -504,28 +509,34 @@ class MarionetteTestCase(CommonTestCase)
else:
raise TimeoutException("wait_for_condition timed out")
class MarionetteJSTestCase(CommonTestCase):
match_re = re.compile(r"test_(.*)\.js$")
- def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs):
+ def __init__(self, marionette_weakref, httpd_weakref, methodName='runTest',
+ jsFile=None, **kwargs):
assert(jsFile)
self.jsFile = jsFile
+ self._httpd_weakref = httpd_weakref
+ self.httpd = None
self._marionette_weakref = marionette_weakref
self.marionette = None
super(MarionetteJSTestCase, self).__init__(methodName)
@classmethod
def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
- testvars, **kwargs):
- suite.addTest(cls(weakref.ref(marionette), jsFile=filepath, **kwargs))
+ httpd, testvars, **kwargs):
+ suite.addTest(cls(weakref.ref(marionette),
+ weakref.ref(httpd),
+ jsFile=filepath,
+ **kwargs))
def runTest(self):
if self.marionette.session is None:
self.marionette.start_session()
self.marionette.execute_script(
"log('TEST-START: {}');".format(self.jsFile.replace('\\', '\\\\')),
sandbox="simpletest")
--- a/testing/marionette/harness/marionette/runner/base.py
+++ b/testing/marionette/harness/marionette/runner/base.py
@@ -992,16 +992,17 @@ class BaseMarionetteTestRunner(object):
mod_name = os.path.splitext(os.path.split(filepath)[-1])[0]
for handler in self.test_handlers:
if handler.match(os.path.basename(filepath)):
handler.add_tests_to_suite(mod_name,
filepath,
suite,
testloader,
self.marionette,
+ self.httpd,
self.testvars,
**self.test_kwargs)
break
if suite.countTestCases():
runner = self.textrunnerclass(logger=self.logger,
marionette=self.marionette,
capabilities=self.capabilities,
--- a/testing/marionette/harness/marionette/runner/httpd.py
+++ b/testing/marionette/harness/marionette/runner/httpd.py
@@ -45,16 +45,20 @@ class FixtureServer(object):
return self._server is not None
def get_url(self, path="/"):
if not self.alive:
raise Exception("Server not started")
return self._server.get_url(path)
@property
+ def router(self):
+ return self._server.router
+
+ @property
def routes(self):
return self._server.router.routes
@handlers.handler
def upload_handler(request, response):
return 200, [], [request.headers.get("Content-Type")] or []
--- a/testing/marionette/harness/marionette/tests/harness_unit/conftest.py
+++ b/testing/marionette/harness/marionette/tests/harness_unit/conftest.py
@@ -1,16 +1,18 @@
# 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 pytest
from mock import Mock, MagicMock
from marionette_driver.marionette import Marionette
+from marionette.runner.httpd import FixtureServer
@pytest.fixture(scope='module')
def logger():
"""
Fake logger to help with mocking out other runner-related classes.
"""
import mozlog
@@ -78,16 +80,24 @@ def mach_parsed_kwargs(logger):
'this_chunk': None,
'timeout': None,
'total_chunks': None,
'verbose': None,
'workspace': None,
'logger': logger,
}
+
+@pytest.fixture
+def mock_httpd(request):
+ """ Mock httpd instance """
+ httpd = MagicMock(spec=FixtureServer)
+ return httpd
+
+
@pytest.fixture
def mock_marionette(request):
""" Mock marionette instance """
marionette = MagicMock(spec=Marionette)
if 'has_crashed' in request.funcargnames:
marionette.check_for_crash.return_value = request.getfuncargvalue(
'has_crashed'
)
--- a/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_test_result.py
+++ b/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_test_result.py
@@ -15,17 +15,18 @@ def empty_marionette_testcase():
def test_nothing(self):
pass
return EmptyTestCase
@pytest.fixture
def empty_marionette_test(mock_marionette, empty_marionette_testcase):
- return empty_marionette_testcase(lambda: mock_marionette, 'test_nothing')
+ return empty_marionette_testcase(lambda: mock_marionette, lambda: mock_httpd,
+ 'test_nothing')
@pytest.mark.parametrize("has_crashed", [True, False])
def test_crash_is_recorded_as_error(empty_marionette_test,
logger,
has_crashed):
""" Number of errors is incremented by stopTest iff has_crashed is true """
# collect results from the empty test
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette/tests/unit/test_httpd.py
@@ -0,0 +1,32 @@
+# 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 marionette import MarionetteTestCase
+from marionette_driver import By
+
+
+class TestHttpdServer(MarionetteTestCase):
+
+ def test_handler(self):
+ status = {"count": 0}
+
+ def handler(request, response):
+ status["count"] += 1
+
+ response.headers.set("Content-Type", "text/html")
+ response.content = "<html><body><p id=\"count\">{}</p></body></html>".format(
+ status["count"])
+
+ return ()
+
+ route = ("GET", "/httpd/test_handler", handler)
+ self.httpd.router.register(*route)
+
+ url = self.marionette.absolute_url("httpd/test_handler")
+
+ for counter in range(0, 5):
+ self.marionette.navigate(url)
+ self.assertEqual(status["count"], counter + 1)
+ elem = self.marionette.find_element(By.ID, "count")
+ self.assertEqual(elem.text, str(counter + 1))
--- a/testing/marionette/harness/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette/tests/unit/unit-tests.ini
@@ -135,9 +135,9 @@ skip-if = buildapp == 'b2g' || appname =
[test_shadow_dom.py]
[test_chrome.py]
skip-if = buildapp == 'b2g' || appname == 'fennec'
[test_addons.py]
[test_select.py]
-
+[test_httpd.py]