Bug 1445944 - [mozrunner] Convert mozrunner unittests to the pytest format r=davehunt
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 12 Apr 2018 15:14:03 -0400
changeset 467468 917baaf08d71cf0e16a53992a33c4500d6029ba9
parent 467467 eeb6b72619b6c696b6435128fd79d888ed86d221
child 467469 df5d226d1df3204b7fb4b975e7075a3a3e7a9775
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdavehunt
bugs1445944
milestone61.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 1445944 - [mozrunner] Convert mozrunner unittests to the pytest format r=davehunt This will make it easier to add the ChromeRunner tests in the next couple of commits. MozReview-Commit-ID: 2Nfz92FStSX
testing/mozbase/mozrunner/tests/conftest.py
testing/mozbase/mozrunner/tests/mozrunnertest.py
testing/mozbase/mozrunner/tests/test_crash.py
testing/mozbase/mozrunner/tests/test_interactive.py
testing/mozbase/mozrunner/tests/test_start.py
testing/mozbase/mozrunner/tests/test_states.py
testing/mozbase/mozrunner/tests/test_stop.py
testing/mozbase/mozrunner/tests/test_threads.py
testing/mozbase/mozrunner/tests/test_wait.py
rename from testing/mozbase/mozrunner/tests/mozrunnertest.py
rename to testing/mozbase/mozrunner/tests/conftest.py
--- a/testing/mozbase/mozrunner/tests/mozrunnertest.py
+++ b/testing/mozbase/mozrunner/tests/conftest.py
@@ -1,36 +1,71 @@
 # 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 __future__ import absolute_import
 
 import os
-import unittest
+import threading
+from time import sleep
 
 import mozprofile
 import mozrunner
+import pytest
+from moztest.selftest import fixtures
+
+
+@pytest.fixture
+def profile():
+    return mozprofile.FirefoxProfile()
+
+
+@pytest.fixture
+def get_binary():
+    if 'BROWSER_PATH' in os.environ:
+        os.environ['GECKO_BINARY_PATH'] = os.environ['BROWSER_PATH']
+
+    def inner(app):
+        if app != 'firefox':
+            pytest.xfail(reason="{} support not implemented".format(app))
+
+        binary = fixtures.binary()
+        if not binary:
+            pytest.skip("could not find a {} binary".format(app))
+        return binary
+    return inner
 
 
-@unittest.skipIf(not os.environ.get('BROWSER_PATH'),
-                 'No binary has been specified.')
-class MozrunnerTestCase(unittest.TestCase):
+@pytest.fixture
+def runner(profile, get_binary):
+    binary = get_binary('firefox')
+    return mozrunner.FirefoxRunner(binary, profile=profile)
+
 
-    def setUp(self):
-        self.pids = []
-        self.threads = []
-
-        self.profile = mozprofile.FirefoxProfile()
-        self.runner = mozrunner.FirefoxRunner(os.environ['BROWSER_PATH'],
-                                              profile=self.profile)
+class RunnerThread(threading.Thread):
+    def __init__(self, runner, start=False, timeout=1):
+        threading.Thread.__init__(self)
+        self.runner = runner
+        self.timeout = timeout
+        self.do_start = start
 
-    def tearDown(self):
-        for thread in self.threads:
-            thread.join()
+    def run(self):
+        sleep(self.timeout)
+        if self.do_start:
+            self.runner.start()
+        else:
+            self.runner.stop()
 
-        self.runner.cleanup()
 
-        # Clean-up any left over and running processes
-        for pid in self.pids:
-            # TODO: Bug 925408
-            # mozprocess is not able yet to kill specific processes
-            pass
+@pytest.fixture
+def create_thread():
+    threads = []
+
+    def inner(*args, **kwargs):
+        thread = RunnerThread(*args, **kwargs)
+        threads.append(thread)
+        return thread
+
+    yield inner
+
+    for thread in threads:
+        thread.join()
--- a/testing/mozbase/mozrunner/tests/test_crash.py
+++ b/testing/mozbase/mozrunner/tests/test_crash.py
@@ -1,44 +1,35 @@
 #!/usr/bin/env python
 # 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 __future__ import absolute_import
 
-import mock
+from mock import patch
+
 import mozunit
-
-import mozrunnertest
+import pytest
 
 
-class MozrunnerCrashTestCase(mozrunnertest.MozrunnerTestCase):
-
-    @mock.patch('mozcrash.log_crashes', return_value=2)
-    def test_crash_count_with_logger(self, log_crashes):
-        self.assertEqual(self.runner.crashed, 0)
-        self.assertEqual(self.runner.check_for_crashes(), 2)
-        self.assertEqual(self.runner.crashed, 2)
-        self.assertEqual(self.runner.check_for_crashes(), 2)
-        self.assertEqual(self.runner.crashed, 4)
-
-        log_crashes.return_value = 0
-        self.assertEqual(self.runner.check_for_crashes(), 0)
-        self.assertEqual(self.runner.crashed, 4)
+@pytest.mark.parametrize('logger', [True, False])
+def test_crash_count_with_or_without_logger(runner, logger):
+    if not logger:
+        runner.logger = None
+        fn = 'check_for_crashes'
+    else:
+        fn = 'log_crashes'
 
-    @mock.patch('mozcrash.check_for_crashes', return_value=2)
-    def test_crash_count_without_logger(self, check_for_crashes):
-        self.runner.logger = None
+    with patch('mozcrash.{}'.format(fn), return_value=2) as mock:
+        assert runner.crashed == 0
+        assert runner.check_for_crashes() == 2
+        assert runner.crashed == 2
+        assert runner.check_for_crashes() == 2
+        assert runner.crashed == 4
 
-        self.assertEqual(self.runner.crashed, 0)
-        self.assertEqual(self.runner.check_for_crashes(), 2)
-        self.assertEqual(self.runner.crashed, 2)
-        self.assertEqual(self.runner.check_for_crashes(), 2)
-        self.assertEqual(self.runner.crashed, 4)
-
-        check_for_crashes.return_value = 0
-        self.assertEqual(self.runner.check_for_crashes(), 0)
-        self.assertEqual(self.runner.crashed, 4)
+        mock.return_value = 0
+        assert runner.check_for_crashes() == 0
+        assert runner.crashed == 4
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_interactive.py
+++ b/testing/mozbase/mozrunner/tests/test_interactive.py
@@ -1,61 +1,42 @@
 #!/usr/bin/env python
 
 from __future__ import absolute_import
 
-import threading
 from time import sleep
 
 import mozunit
 
-import mozrunnertest
 
-
-class RunnerThread(threading.Thread):
+def test_run_interactive(runner, create_thread):
+    """Bug 965183: Run process in interactive mode and call wait()"""
+    runner.start(interactive=True)
 
-    def __init__(self, runner, timeout=10):
-        threading.Thread.__init__(self)
-        self.runner = runner
-        self.timeout = timeout
+    thread = create_thread(runner, timeout=2)
+    thread.start()
 
-    def run(self):
-        sleep(self.timeout)
-        self.runner.stop()
+    # This is a blocking call. So the process should be killed by the thread
+    runner.wait()
+    thread.join()
+    assert not runner.is_running()
 
 
-class MozrunnerInteractiveTestCase(mozrunnertest.MozrunnerTestCase):
-
-    def test_run_interactive(self):
-        """Bug 965183: Run process in interactive mode and call wait()"""
-        pid = self.runner.start(interactive=True)
-        self.pids.append(pid)
+def test_stop_interactive(runner):
+    """Bug 965183: Explicitely stop process in interactive mode"""
+    runner.start(interactive=True)
+    runner.stop()
 
-        thread = RunnerThread(self.runner, 5)
-        self.threads.append(thread)
-        thread.start()
-
-        # This is a blocking call. So the process should be killed by the thread
-        self.runner.wait()
-        thread.join()
-        self.assertFalse(self.runner.is_running())
 
-    def test_stop_interactive(self):
-        """Bug 965183: Explicitely stop process in interactive mode"""
-        pid = self.runner.start(interactive=True)
-        self.pids.append(pid)
-
-        self.runner.stop()
+def test_wait_after_process_finished(runner):
+    """Wait after the process has been stopped should not raise an error"""
+    runner.start(interactive=True)
+    sleep(1)
+    runner.process_handler.kill()
 
-    def test_wait_after_process_finished(self):
-        """Wait after the process has been stopped should not raise an error"""
-        self.runner.start(interactive=True)
-        sleep(5)
-        self.runner.process_handler.kill()
+    returncode = runner.wait(1)
 
-        returncode = self.runner.wait(1)
-
-        self.assertNotIn(returncode, [None, 0])
-        self.assertIsNotNone(self.runner.process_handler)
+    assert returncode not in [None, 0]
+    assert runner.process_handler is not None
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_start.py
+++ b/testing/mozbase/mozrunner/tests/test_start.py
@@ -1,53 +1,52 @@
 #!/usr/bin/env python
 
 from __future__ import absolute_import
 
 from time import sleep
 
 import mozunit
 
-import mozrunnertest
+
+def test_start_process(runner):
+    """Start the process and test properties"""
+    assert runner.process_handler is None
+
+    runner.start()
+
+    assert runner.is_running()
+    assert runner.process_handler is not None
 
 
-class MozrunnerStartTestCase(mozrunnertest.MozrunnerTestCase):
-
-    def test_start_process(self):
-        """Start the process and test properties"""
-        self.assertIsNone(self.runner.process_handler)
-
-        self.runner.start()
+def test_start_process_called_twice(runner):
+    """Start the process twice and test that first process is gone"""
+    runner.start()
+    # Bug 925480
+    # Make a copy until mozprocess can kill a specific process
+    process_handler = runner.process_handler
 
-        self.assertTrue(self.runner.is_running())
-        self.assertIsNotNone(self.runner.process_handler)
+    runner.start()
 
-    def test_start_process_called_twice(self):
-        """Start the process twice and test that first process is gone"""
-        self.runner.start()
-        # Bug 925480
-        # Make a copy until mozprocess can kill a specific process
-        process_handler = self.runner.process_handler
+    try:
+        assert process_handler.wait(1) not in [None, 0]
+    finally:
+        process_handler.kill()
+
 
-        self.runner.start()
+def test_start_with_timeout(runner):
+    """Start the process and set a timeout"""
+    runner.start(timeout=0.1)
+    sleep(1)
 
-        try:
-            self.assertNotIn(process_handler.wait(1), [None, 0])
-        finally:
-            process_handler.kill()
+    assert not runner.is_running()
 
-    def test_start_with_timeout(self):
-        """Start the process and set a timeout"""
-        self.runner.start(timeout=2)
-        sleep(5)
-
-        self.assertFalse(self.runner.is_running())
 
-    def test_start_with_outputTimeout(self):
-        """Start the process and set a timeout"""
-        self.runner.start(outputTimeout=2)
-        sleep(15)
+def test_start_with_outputTimeout(runner):
+    """Start the process and set a timeout"""
+    runner.start(outputTimeout=0.1)
+    sleep(1)
 
-        self.assertFalse(self.runner.is_running())
+    assert not runner.is_running()
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_states.py
+++ b/testing/mozbase/mozrunner/tests/test_states.py
@@ -1,26 +1,25 @@
 #!/usr/bin/env python
 
 from __future__ import absolute_import
 
-import mozrunner
+import mozunit
+import pytest
 
-import mozunit
-
-import mozrunnertest
+from mozrunner import RunnerNotStartedError
 
 
-class MozrunnerStatesTestCase(mozrunnertest.MozrunnerTestCase):
+def test_errors_before_start(runner):
+    """Bug 965714: Not started errors before start() is called"""
 
-    def test_errors_before_start(self):
-        """Bug 965714: Not started errors before start() is called"""
+    with pytest.raises(RunnerNotStartedError):
+        runner.is_running()
 
-        def test_returncode():
-            return self.runner.returncode
+    with pytest.raises(RunnerNotStartedError):
+        runner.returncode
 
-        self.assertRaises(mozrunner.RunnerNotStartedError, self.runner.is_running)
-        self.assertRaises(mozrunner.RunnerNotStartedError, test_returncode)
-        self.assertRaises(mozrunner.RunnerNotStartedError, self.runner.wait)
+    with pytest.raises(RunnerNotStartedError):
+        runner.wait()
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_stop.py
+++ b/testing/mozbase/mozrunner/tests/test_stop.py
@@ -4,44 +4,40 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
 import signal
 
 import mozunit
 
-import mozrunnertest
+
+def test_stop_process(runner):
+    """Stop the process and test properties"""
+    runner.start()
+    returncode = runner.stop()
+
+    assert not runner.is_running()
+    assert returncode not in [None, 0]
+    assert runner.returncode == returncode
+    assert runner.process_handler is not None
+    assert runner.wait(1) == returncode
 
 
-class MozrunnerStopTestCase(mozrunnertest.MozrunnerTestCase):
-
-    def test_stop_process(self):
-        """Stop the process and test properties"""
-        self.runner.start()
-        returncode = self.runner.stop()
+def test_stop_before_start(runner):
+    """Stop the process before it gets started should not raise an error"""
+    runner.stop()
 
-        self.assertFalse(self.runner.is_running())
-        self.assertNotIn(returncode, [None, 0])
-        self.assertEqual(self.runner.returncode, returncode)
-        self.assertIsNotNone(self.runner.process_handler)
-
-        self.assertEqual(self.runner.wait(1), returncode)
 
-    def test_stop_before_start(self):
-        """Stop the process before it gets started should not raise an error"""
-        self.runner.stop()
+def test_stop_process_custom_signal(runner):
+    """Stop the process via a custom signal and test properties"""
+    runner.start()
+    returncode = runner.stop(signal.SIGTERM)
 
-    def test_stop_process_custom_signal(self):
-        """Stop the process via a custom signal and test properties"""
-        self.runner.start()
-        returncode = self.runner.stop(signal.SIGTERM)
-
-        self.assertFalse(self.runner.is_running())
-        self.assertNotIn(returncode, [None, 0])
-        self.assertEqual(self.runner.returncode, returncode)
-        self.assertIsNotNone(self.runner.process_handler)
-
-        self.assertEqual(self.runner.wait(1), returncode)
+    assert not runner.is_running()
+    assert returncode not in [None, 0]
+    assert runner.returncode == returncode
+    assert runner.process_handler is not None
+    assert runner.wait(1) == returncode
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_threads.py
+++ b/testing/mozbase/mozrunner/tests/test_threads.py
@@ -1,81 +1,59 @@
 #!/usr/bin/env python
 # 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 __future__ import absolute_import
 
-import threading
-from time import sleep
-
 import mozunit
 
-import mozrunnertest
-
 
-class RunnerThread(threading.Thread):
+def test_process_start_via_thread(runner, create_thread):
+    """Start the runner via a thread"""
+    thread = create_thread(runner, True, 2)
 
-    def __init__(self, runner, do_start, timeout=10):
-        threading.Thread.__init__(self)
-        self.runner = runner
-        self.timeout = timeout
-        self.do_start = do_start
+    thread.start()
+    thread.join()
 
-    def run(self):
-        sleep(self.timeout)
-        if self.do_start:
-            self.runner.start()
-        else:
-            self.runner.stop()
+    assert runner.is_running()
 
 
-class MozrunnerThreadsTestCase(mozrunnertest.MozrunnerTestCase):
-
-    def test_process_start_via_thread(self):
-        """Start the runner via a thread"""
-        thread = RunnerThread(self.runner, True, 2)
-        self.threads.append(thread)
-
-        thread.start()
-        thread.join()
-
-        self.assertTrue(self.runner.is_running())
-
-    def test_process_stop_via_multiple_threads(self):
-        """Stop the runner via multiple threads"""
-        self.runner.start()
-        for i in range(5):
-            thread = RunnerThread(self.runner, False, 5)
-            self.threads.append(thread)
-            thread.start()
-
-        # Wait until the process has been stopped by another thread
-        for thread in self.threads:
-            thread.join()
-        returncode = self.runner.wait(2)
-
-        self.assertNotIn(returncode, [None, 0])
-        self.assertEqual(self.runner.returncode, returncode)
-        self.assertIsNotNone(self.runner.process_handler)
-        self.assertEqual(self.runner.wait(10), returncode)
-
-    def test_process_post_stop_via_thread(self):
-        """Stop the runner and try it again with a thread a bit later"""
-        self.runner.start()
-        thread = RunnerThread(self.runner, False, 5)
-        self.threads.append(thread)
+def test_process_stop_via_multiple_threads(runner, create_thread):
+    """Stop the runner via multiple threads"""
+    runner.start()
+    threads = []
+    for i in range(5):
+        thread = create_thread(runner, False, 5)
+        threads.append(thread)
         thread.start()
 
-        # Wait a bit to start the application gets started
-        self.runner.wait(2)
-        returncode = self.runner.stop()
+    # Wait until the process has been stopped by another thread
+    for thread in threads:
         thread.join()
+    returncode = runner.wait(1)
+
+    assert returncode not in [None, 0]
+    assert runner.returncode == returncode
+    assert runner.process_handler is not None
+    assert runner.wait(2) == returncode
+
 
-        self.assertNotIn(returncode, [None, 0])
-        self.assertEqual(self.runner.returncode, returncode)
-        self.assertIsNotNone(self.runner.process_handler)
-        self.assertEqual(self.runner.wait(10), returncode)
+def test_process_post_stop_via_thread(runner, create_thread):
+    """Stop the runner and try it again with a thread a bit later"""
+    runner.start()
+    thread = create_thread(runner, False, 5)
+    thread.start()
+
+    # Wait a bit to start the application gets started
+    runner.wait(1)
+    returncode = runner.stop()
+    thread.join()
+
+    assert returncode not in [None, 0]
+    assert runner.returncode == returncode
+    assert runner.process_handler is not None
+    assert runner.wait(2) == returncode
 
 
 if __name__ == '__main__':
     mozunit.main()
--- a/testing/mozbase/mozrunner/tests/test_wait.py
+++ b/testing/mozbase/mozrunner/tests/test_wait.py
@@ -1,36 +1,34 @@
 #!/usr/bin/env python
 # 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 __future__ import absolute_import
 
 import mozunit
-import mozrunnertest
 
 
-class MozrunnerWaitTestCase(mozrunnertest.MozrunnerTestCase):
+def test_wait_while_running(runner):
+    """Wait for the process while it is running"""
+    runner.start()
+    returncode = runner.wait(1)
 
-    def test_wait_while_running(self):
-        """Wait for the process while it is running"""
-        self.runner.start()
-        returncode = self.runner.wait(1)
+    assert runner.is_running()
+    assert returncode is None
+    assert runner.returncode == returncode
+    assert runner.process_handler is not None
 
-        self.assertTrue(self.runner.is_running())
-        self.assertEqual(returncode, None)
-        self.assertEqual(self.runner.returncode, returncode)
-        self.assertIsNotNone(self.runner.process_handler)
 
-    def test_wait_after_process_finished(self):
-        """Bug 965714: wait() after stop should not raise an error"""
-        self.runner.start()
-        self.runner.process_handler.kill()
+def test_wait_after_process_finished(runner):
+    """Bug 965714: wait() after stop should not raise an error"""
+    runner.start()
+    runner.process_handler.kill()
 
-        returncode = self.runner.wait(1)
+    returncode = runner.wait(1)
 
-        self.assertNotIn(returncode, [None, 0])
-        self.assertIsNotNone(self.runner.process_handler)
+    assert returncode not in [None, 0]
+    assert runner.process_handler is not None
 
 
 if __name__ == '__main__':
     mozunit.main()