| Index: testing/legion/legion_test_case.py
|
| diff --git a/testing/legion/legion_test_case.py b/testing/legion/legion_test_case.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9514e8e19be7c57d31ec8ffff7b6e0c00cd6f906
|
| --- /dev/null
|
| +++ b/testing/legion/legion_test_case.py
|
| @@ -0,0 +1,135 @@
|
| +# Copyright 2015 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""Adds unittest-esque functionality to Legion."""
|
| +
|
| +import argparse
|
| +import logging
|
| +import sys
|
| +import unittest
|
| +
|
| +#pylint: disable=relative-import
|
| +import common_lib
|
| +import task_controller
|
| +import task_registration_server
|
| +
|
| +BANNER_WIDTH = 80
|
| +
|
| +
|
| +class TestCase(unittest.TestCase):
|
| + """Test case class with added Legion support."""
|
| +
|
| + _registration_server = None
|
| + _initialized = False
|
| +
|
| + @classmethod
|
| + def __new__(cls, *args, **kwargs):
|
| + """Initialize the class and return a new instance."""
|
| + cls._InitializeClass()
|
| + return super(TestCase, cls).__new__(*args, **kwargs)
|
| +
|
| + def __init__(self, test_name='runTest'):
|
| + super(TestCase, self).__init__(test_name)
|
| + method = getattr(self, test_name, None)
|
| + if method:
|
| + # Install the _RunTest method
|
| + self._TestMethod = method
|
| + setattr(self, test_name, self._RunTest)
|
| +
|
| + def _RunTest(self):
|
| + """Runs the test method and provides banner info and error reporting."""
|
| + self._LogInfoBanner(self._testMethodName, self.shortDescription())
|
| + try:
|
| + return self._TestMethod()
|
| + except:
|
| + exc_info = sys.exc_info()
|
| + logging.error('', exc_info=exc_info)
|
| + raise exc_info[0], exc_info[1], exc_info[2]
|
| +
|
| + @classmethod
|
| + def _InitializeClass(cls):
|
| + """Handles class level initialization.
|
| +
|
| + There are 2 types of setup/teardown methods that always need to be run:
|
| + 1) Framework level setup/teardown
|
| + 2) Test case level setup/teardown
|
| +
|
| + This method installs handlers in place of setUpClass and tearDownClass that
|
| + will ensure both types of setup/teardown methods are called correctly.
|
| + """
|
| + if cls._initialized:
|
| + return
|
| + cls._OriginalSetUpClassMethod = cls.setUpClass
|
| + cls.setUpClass = cls._HandleSetUpClass
|
| + cls._OriginalTearDownClassMethod = cls.tearDownClass
|
| + cls.tearDownClass = cls._HandleTearDownClass
|
| + cls._initialized = True
|
| +
|
| + @classmethod
|
| + def _LogInfoBanner(cls, method_name, method_doc=None):
|
| + """Formats and logs test case information."""
|
| + logging.info('*' * BANNER_WIDTH)
|
| + logging.info(method_name.center(BANNER_WIDTH))
|
| + if method_doc:
|
| + for line in method_doc.split('\n'):
|
| + logging.info(line.center(BANNER_WIDTH))
|
| + logging.info('*' * BANNER_WIDTH)
|
| +
|
| + @classmethod
|
| + def CreateTask(cls, *args, **kwargs):
|
| + """Convenience method to create a new task."""
|
| + task = task_controller.TaskController(*args, **kwargs)
|
| + cls._registration_server.RegisterTaskCallback(
|
| + task.otp, task.OnConnect)
|
| + return task
|
| +
|
| + @classmethod
|
| + def _SetUpFramework(cls):
|
| + """Perform the framework-specific setup operations."""
|
| + cls._registration_server = (
|
| + task_registration_server.TaskRegistrationServer())
|
| + cls._registration_server.Start()
|
| +
|
| + @classmethod
|
| + def _TearDownFramework(cls):
|
| + """Perform the framework-specific teardown operations."""
|
| + if cls._registration_server:
|
| + cls._registration_server.Shutdown()
|
| + task_controller.TaskController.ReleaseAllTasks()
|
| +
|
| + @classmethod
|
| + def _HandleSetUpClass(cls):
|
| + """Performs common class-level setup operations.
|
| +
|
| + This method performs test-wide setup such as starting the registration
|
| + server and then calls the original setUpClass method."""
|
| + try:
|
| + common_lib.InitLogging()
|
| + cls._LogInfoBanner('setUpClass', 'Performs class level setup.')
|
| + cls._SetUpFramework()
|
| + cls._OriginalSetUpClassMethod()
|
| + except:
|
| + # Make sure we tear down in case of any exceptions
|
| + cls._HandleTearDownClass(setup_failed=True)
|
| + exc_info = sys.exc_info()
|
| + logging.error('', exc_info=exc_info)
|
| + raise exc_info[0], exc_info[1], exc_info[2]
|
| +
|
| + @classmethod
|
| + def _HandleTearDownClass(cls, setup_failed=False):
|
| + """Performs common class-level tear down operations.
|
| +
|
| + This method calls the original tearDownClass then performs test-wide
|
| + tear down such as stopping the registration server.
|
| + """
|
| + cls._LogInfoBanner('tearDownClass', 'Performs class level tear down.')
|
| + try:
|
| + if not setup_failed:
|
| + cls._OriginalTearDownClassMethod()
|
| + finally:
|
| + cls._TearDownFramework()
|
| +
|
| +
|
| +def main():
|
| + unittest.main(verbosity=0, argv=sys.argv[:1])
|
|
|