Bug 1227367 - Test MarionetteTestRunner's test_handlers and testvars; r=automatedtester draft
authorMaja Frydrychowicz <mjzffr@gmail.com>
Thu, 31 Mar 2016 00:35:09 -0400
changeset 347422 d51ca314489d9f480409466530ed07f5a2af94a3
parent 347421 6bb34324a5bd855ef8ac5a9eba3e624db5583237
child 517629 c6e34f1de13528630477a992ca8cbc1d2bb9aa6f
push id14580
push usermjzffr@gmail.com
push dateMon, 04 Apr 2016 22:00:08 +0000
reviewersautomatedtester
bugs1227367
milestone48.0a1
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
testing/marionette/harness/marionette/runner/base.py
testing/marionette/harness/marionette/tests/harness_unit/test_marionette_runner.py
--- 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__]))