Bug 1445944 - [mozrunner] Convert mozrunner unittests to the pytest format draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 12 Apr 2018 15:14:03 -0400
changeset 783082 7e03e2584992c70d73f120df0836678794f1c868
parent 783081 a5deca5affc9d7a6000b5e4f1524a7525ef75fbe
child 783083 26ff907b3bc8fcc9d801af7673c76663b5b25544
child 783203 32923906064ecdfa0899e7c5e53209764840cc1e
push id106597
push userahalberstadt@mozilla.com
push dateMon, 16 Apr 2018 14:41:52 +0000
bugs1445944
milestone61.0a1
Bug 1445944 - [mozrunner] Convert mozrunner unittests to the pytest format 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()