Fix -r option breakage caused by TestRunner.register_controller.
Unregister controllers at the end of TestRunner.run so controller
objects are properly recreated for each TestRunner.run call.
Renamed clean_up to unregister_controller to better represent its
purpose.
Added a test to guard against this bug. The tests will have less
external dependencies once TestRunner can take test class instances
directly.
Bug=28351141
Change-Id: Ife542b7d92e51c9a6f47fab9ac710840016f64fe
diff --git a/acts/framework/acts/test_runner.py b/acts/framework/acts/test_runner.py
index a965f5b..534ce29 100644
--- a/acts/framework/acts/test_runner.py
+++ b/acts/framework/acts/test_runner.py
@@ -217,6 +217,20 @@
self.controller_destructors[module_ref_name] = destroy_func
return objects
+ def unregister_controllers(self):
+ """Destroy controller objects and clear internal registry.
+
+ This will be called at the end of each TestRunner.run call.
+ """
+ for name, destroy in self.controller_destructors.items():
+ try:
+ self.log.debug("Destroying %s.", name)
+ destroy(self.controller_registry[name])
+ except:
+ self.log.exception("Exception occurred destroying %s.", name)
+ self.controller_registry = {}
+ self.controller_destructors = {}
+
def parse_config(self, test_configs):
"""Parses the test configuration and unpacks objects and parameters
into a dictionary to be passed to test classes.
@@ -298,57 +312,56 @@
raise e
def run(self):
- """Kicks off the test run.
+ """Executes test cases.
This will instantiate controller and test classes, and execute test
- classes. A call to TestRunner.run should always be accompanied by a
- call to TestRunner.stop.
+ classes. This can be called multiple times to repeatly execute the
+ requested test cases.
+
+ A call to TestRunner.stop should eventually happen to conclude the life
+ cycle of a TestRunner.
"""
if not self.running:
self.running = True
- # Initialize controller objects and pack appropriate objects/params to
- # be passed to test class.
+ # Initialize controller objects and pack appropriate objects/params
+ # to be passed to test class.
self.parse_config(self.test_configs)
t_configs = self.test_configs[keys.Config.key_test_paths.value]
self.test_classes = self.import_test_modules(t_configs)
self.log.debug("Executing run list %s.", self.run_list)
- for test_cls_name, test_case_names in self.run_list:
- if not self.running:
- break
- if test_case_names:
- self.log.debug("Executing test cases %s in test class %s.",
- test_case_names,
- test_cls_name)
- else:
- self.log.debug("Executing test class %s", test_cls_name)
- try:
- self.run_test_class(test_cls_name, test_case_names)
- except signals.TestAbortAll as e:
- self.log.warning(("Abort all subsequent test classes. Reason: "
- "%s"), e)
- raise
+ try:
+ for test_cls_name, test_case_names in self.run_list:
+ if not self.running:
+ break
+ if test_case_names:
+ self.log.debug("Executing test cases %s in test class %s.",
+ test_case_names,
+ test_cls_name)
+ else:
+ self.log.debug("Executing test class %s", test_cls_name)
+ try:
+ self.run_test_class(test_cls_name, test_case_names)
+ except signals.TestAbortAll as e:
+ self.log.warning(("Abort all subsequent test classes. Reason: "
+ "%s"), e)
+ raise
+ finally:
+ self.unregister_controllers()
def stop(self):
"""Releases resources from test run. Should always be called after
TestRunner.run finishes.
+
+ This function concludes a test run and writes out a test report.
"""
if self.running:
msg = "\nSummary for test run %s: %s\n" % (self.id,
self.results.summary_str())
self._write_results_json_str()
self.log.info(msg.strip())
- self.clean_up()
logger.kill_test_logger(self.log)
self.running = False
- def clean_up(self):
- for name, destroy in self.controller_destructors.items():
- try:
- self.log.debug("Destroying %s.", name)
- destroy(self.controller_registry[name])
- except:
- self.log.exception("Exception occurred destroying %s.", name)
-
def _write_results_json_str(self):
"""Writes out a json file with the test result info for easy parsing.
diff --git a/acts/framework/tests/HelloWorldTest.py b/acts/framework/tests/IntegrationTest.py
similarity index 87%
rename from acts/framework/tests/HelloWorldTest.py
rename to acts/framework/tests/IntegrationTest.py
index 27133ab..519dd46 100755
--- a/acts/framework/tests/HelloWorldTest.py
+++ b/acts/framework/tests/IntegrationTest.py
@@ -17,7 +17,12 @@
from acts import asserts
from acts import base_test
-class HelloWorldTest(base_test.BaseTestClass):
+import mock_controller
+
+class IntegrationTest(base_test.BaseTestClass):
+
+ def setup_class(self):
+ self.register_controller(mock_controller)
def test_hello_world(self):
asserts.assert_equal(self.user_params["icecream"], 42)
diff --git a/acts/framework/tests/acts_hello_world_test.py b/acts/framework/tests/acts_integration_test.py
similarity index 82%
rename from acts/framework/tests/acts_hello_world_test.py
rename to acts/framework/tests/acts_integration_test.py
index 81b1d11..fa344a1 100644
--- a/acts/framework/tests/acts_hello_world_test.py
+++ b/acts/framework/tests/acts_integration_test.py
@@ -18,12 +18,12 @@
import subprocess
import unittest
-class ActsHelloWorldTest(unittest.TestCase):
- """Execute a simple hello world ACTS test to make sure the basic workflow
- of ACTS is intact.
+class ActsIntegrationTest(unittest.TestCase):
+ """Execute a simple ACTS test to make sure the basic workflow of ACTS is
+ intact.
"""
def test_acts(self):
- cmd = "act.py -c acts_sanity_test_config.json -tc HelloWorldTest"
+ cmd = "act.py -c acts_sanity_test_config.json -tc IntegrationTest"
subprocess.check_call([cmd], shell=True)
with open("/tmp/logs/Sanity/latest/test_run_summary.json", 'r') as f:
results = json.load(f)
diff --git a/acts/framework/tests/acts_sanity_test_config.json b/acts/framework/tests/acts_sanity_test_config.json
index fc06226..d2a1d74 100644
--- a/acts/framework/tests/acts_sanity_test_config.json
+++ b/acts/framework/tests/acts_sanity_test_config.json
@@ -4,7 +4,8 @@
{
"_description": "ACTS sanity test bed, no device needed.",
"name": "Sanity",
- "icecream": 42
+ "icecream": 42,
+ "MagicDevice": ["Magic!"]
}
],
"logpath": "/tmp/logs",
diff --git a/acts/framework/tests/acts_test_runner_test.py b/acts/framework/tests/acts_test_runner_test.py
index a99030b..15263a9 100755
--- a/acts/framework/tests/acts_test_runner_test.py
+++ b/acts/framework/tests/acts_test_runner_test.py
@@ -34,11 +34,13 @@
self.tmp_dir = tempfile.mkdtemp()
self.base_mock_test_config = {
"testbed":{
- "name": "SampleTestBed"
+ "name": "SampleTestBed",
},
"logpath": self.tmp_dir,
"cli_args": None,
- "testpaths": ["../tests/sample"]
+ "testpaths": ["./"],
+ "icecream": 42,
+ "extra_param": "haha"
}
self.mock_run_list = [('SampleTest', None)]
@@ -114,6 +116,25 @@
self.assertEqual(magic_devices[0].magic, "magic1")
self.assertEqual(magic_devices[1].magic, "magic2")
+ def test_run_twice(self):
+ mock_test_config = dict(self.base_mock_test_config)
+ tb_key = keys.Config.key_testbed.value
+ mock_ctrlr_config_name = mock_controller.ACTS_CONTROLLER_CONFIG_NAME
+ mock_test_config[tb_key][mock_ctrlr_config_name] = ["magic1", "magic2"]
+ tr = test_runner.TestRunner(self.base_mock_test_config,
+ [('IntegrationTest', None)])
+ tr.run()
+ self.assertFalse(tr.controller_registry)
+ self.assertFalse(tr.controller_destructors)
+ tr.run()
+ tr.stop()
+ self.assertFalse(tr.controller_registry)
+ self.assertFalse(tr.controller_destructors)
+ results = tr.results.summary_dict()
+ self.assertEqual(results["Requested"], 2)
+ self.assertEqual(results["Executed"], 2)
+ self.assertEqual(results["Passed"], 2)
+
def test_verify_controller_module(self):
test_runner.TestRunner.verify_controller_module(mock_controller)
diff --git a/acts/framework/tests/test_all b/acts/framework/tests/test_all
index 04802a2..afc962c 100755
--- a/acts/framework/tests/test_all
+++ b/acts/framework/tests/test_all
@@ -3,13 +3,13 @@
import sys
import unittest
-import acts_hello_world_test
+import acts_integration_test
import acts_unittest_suite
if __name__ == "__main__":
# This files executes both the unit tests and the integration test.
suite = acts_unittest_suite.compile_suite()
- suite.addTest(acts_hello_world_test.ActsHelloWorldTest("test_acts"))
+ suite.addTest(acts_integration_test.ActsIntegrationTest("test_acts"))
runner = unittest.TextTestRunner()
results = runner.run(suite)
sys.exit(not results.wasSuccessful())