Bug 1227367 - Test MarionetteTestRunner's test_handlers and testvars; r=automatedtester
BaseMarionetteTestRunner sets up an empty list of test_handlers; however
it is essential for any child class have at least one test_handler,
otherwise the harness is busted. So, I added a test to check that
MarionetteTestRunner sets up the expected test_handlers.
In doing so, I refactor BaseMarionetteTestRunner.__init__ to
split out file i/o into other methods so I can mock them out,
which involves modifying testvars code.
So, I also added a test to make sure the parsing of testvars still
works.
MozReview-Commit-ID: GF5MKy8rN8C
--- a/testing/marionette/harness/marionette/runner/base.py
+++ b/testing/marionette/harness/marionette/runner/base.py
@@ -603,59 +603,74 @@ class BaseMarionetteTestRunner(object):
rv['source'] = marionette.page_source
except Exception:
logger = get_default_logger()
logger.warning('Failed to gather test failure debug.', exc_info=True)
return rv
self.result_callbacks.append(gather_debug)
+ # testvars are set up in self.testvars property
+ self._testvars = None
+ self.testvars_paths = testvars
+
+ self.test_handlers = []
+
+ self.reset_test_stats()
+
+ self.logger.info('Using workspace for temporary data: '
+ '"{}"'.format(self.workspace_path))
+
+ if self.emulator and not self.logdir:
+ self.logdir = os.path.join(self.workspace_path or '', 'logcat')
+
+ if not gecko_log:
+ self.gecko_log = os.path.join(self.workspace_path or '', 'gecko.log')
+ else:
+ self.gecko_log = gecko_log
+
+ self.results = []
+
+ @property
+ def testvars(self):
+ if self._testvars is not None:
+ return self._testvars
+
+ self._testvars = {}
+
def update(d, u):
""" Update a dictionary that may contain nested dictionaries. """
for k, v in u.iteritems():
o = d.get(k, {})
if isinstance(v, dict) and isinstance(o, dict):
d[k] = update(d.get(k, {}), v)
else:
d[k] = u[k]
return d
- self.testvars = {}
- if testvars is not None:
- for path in list(testvars):
+ json_testvars = self._load_testvars()
+ for j in json_testvars:
+ self._testvars = update(self._testvars, j)
+ return self._testvars
+
+ def _load_testvars(self):
+ data = []
+ if self.testvars_paths is not None:
+ for path in list(self.testvars_paths):
+ path = os.path.abspath(os.path.expanduser(path))
if not os.path.exists(path):
raise IOError('--testvars file %s does not exist' % path)
try:
with open(path) as f:
- self.testvars = update(self.testvars,
- json.loads(f.read()))
+ data.append(json.loads(f.read()))
except ValueError as e:
raise Exception("JSON file (%s) is not properly "
"formatted: %s" % (os.path.abspath(path),
e.message))
-
- # set up test handlers
- self.test_handlers = []
-
- self.reset_test_stats()
-
- self.logger.info('Using workspace for temporary data: '
- '"{}"'.format(self.workspace_path))
-
- if self.emulator and not self.logdir:
- self.logdir = os.path.join(self.workspace_path or '', 'logcat')
- if self.logdir and not os.access(self.logdir, os.F_OK):
- os.mkdir(self.logdir)
-
- if not gecko_log:
- self.gecko_log = os.path.join(self.workspace_path or '', 'gecko.log')
- else:
- self.gecko_log = gecko_log
-
- self.results = []
+ return data
@property
def capabilities(self):
if self._capabilities:
return self._capabilities
self.marionette.start_session()
self._capabilities = self.marionette.session_capabilities
@@ -718,16 +733,19 @@ class BaseMarionetteTestRunner(object):
self.passed = 0
self.failed = 0
self.unexpected_successes = 0
self.todo = 0
self.skipped = 0
self.failures = []
def _build_kwargs(self):
+ if self.logdir and not os.access(self.logdir, os.F_OK):
+ os.mkdir(self.logdir)
+
kwargs = {
'device_serial': self.device_serial,
'symbols_path': self.symbols_path,
'timeout': self.timeout,
'socket_timeout': self.socket_timeout,
'adb_host': self._adb_host,
'adb_port': self._adb_port,
'prefs': self.prefs,
--- a/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_runner.py
+++ b/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_runner.py
@@ -149,11 +149,45 @@ def test_call_harness_with_parsed_args_y
def test_call_harness_with_no_args_yields_num_failures(runner_class):
with patch('marionette.runtests.MarionetteHarness.parse_args') as parse_args:
parse_args.return_value = {'tests':[]}
failed = MarionetteHarness(runner_class).run()
assert parse_args.call_count == 1
assert failed == 0
+
+def test_harness_sets_up_default_test_handlers(mach_parsed_kwargs):
+ """
+ If the necessary TestCase is not in test_handlers,
+ tests are omitted silently
+ """
+ harness = MarionetteHarness(args=mach_parsed_kwargs)
+ mach_parsed_kwargs.pop('tests')
+ runner = harness._runner_class(**mach_parsed_kwargs)
+ assert marionette_test.MarionetteTestCase in runner.test_handlers
+ assert marionette_test.MarionetteJSTestCase in runner.test_handlers
+
+
+def test_parsing_testvars(mach_parsed_kwargs):
+ mach_parsed_kwargs.pop('tests')
+ testvars_json_loads = [
+ {"wifi":{"ssid": "blah", "keyManagement": "WPA-PSK", "psk": "foo"}},
+ {"wifi":{"PEAP": "bar"}, "device": {"stuff": "buzz"}}
+ ]
+ expected_dict = {
+ "wifi": {
+ "ssid": "blah",
+ "keyManagement": "WPA-PSK",
+ "psk": "foo",
+ "PEAP":"bar"
+ },
+ "device": {"stuff":"buzz"}
+ }
+ with patch('marionette.runtests.MarionetteTestRunner._load_testvars') as load:
+ load.return_value = testvars_json_loads
+ runner = MarionetteTestRunner(**mach_parsed_kwargs)
+ assert runner.testvars == expected_dict
+ assert load.call_count == 1
+
if __name__ == '__main__':
import sys
sys.exit(pytest.main(['--verbose', __file__]))