From 6f60cd87a1ee718f7f5a5ae1339e76ec7411d8e3 Mon Sep 17 00:00:00 2001 From: John-Holt-Tessella Date: Thu, 12 Sep 2019 17:04:09 +0100 Subject: [PATCH 1/4] Test the set of motor at motor level. Also add facility to stop tests --- README.md | 7 +++++ run_tests.py | 27 ++++++++++++++--- tests/galil.py | 64 +++++++++++++++++++++++++++++++++++++++++ utils/channel_access.py | 2 +- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 tests/galil.py diff --git a/README.md b/README.md index ccce050a7..f5fc53119 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,13 @@ By default the framework searches for tests inside `.\tests\`. If you wish to sp >`python run_tests.py -tp C:\my_ioc_tests` will run tests in the `my_ioc_tests` folder. +### Run test but Ask before starting the tests but after the IOC and emmulator are running + +It is sometimes useful to attach a debugger to the test using this option means that the framework will ask to run tests before it starts the setup for the test. +This gives you time to attach a debugger. It also allows you an easy way to set up the system with emmulator and ioc attached to each other for unscripted testing. + +> `python run_tests.py -a will ask if you want to run test before it runs them. + ## Troubleshooting If all tests are failing then it is likely that the PV prefix is incorrect. diff --git a/run_tests.py b/run_tests.py index bfcf79a6e..55b9d4c6a 100644 --- a/run_tests.py +++ b/run_tests.py @@ -7,6 +7,8 @@ import sys import traceback import unittest + +import six import xmlrunner import glob @@ -90,13 +92,14 @@ def make_device_launchers_from_module(test_module, mode): return device_launchers -def load_and_run_tests(test_names, failfast): +def load_and_run_tests(test_names, failfast, ask_before_running_tests): """ Loads and runs the dotted unit tests to be run. Args: test_names: List of dotted unit tests to run. failfast: Determines if tests abort after first failure. + ask_before_running_tests: ask whether to run the tests before running them Returns: boolean: True if all tests pass and false otherwise. @@ -121,12 +124,12 @@ def load_and_run_tests(test_names, failfast): clean_environment() device_launchers = make_device_launchers_from_module(module.file, mode) test_results.append( - run_tests(arguments.prefix, module.tests, device_collection_launcher(device_launchers), failfast)) + run_tests(arguments.prefix, module.tests, device_collection_launcher(device_launchers), failfast, ask_before_running_tests)) return all(test_result is True for test_result in test_results) -def run_tests(prefix, tests_to_run, device_launchers, failfast_switch): +def run_tests(prefix, tests_to_run, device_launchers, failfast_switch, ask_before_running_tests=False): """ Runs dotted unit tests. @@ -135,6 +138,7 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch): tests_to_run: List of dotted unit tests to be run. device_launchers: Context manager that launches the necessary iocs and associated emulators. failfast_switch: Determines if test suit aborts after first failure. + ask_before_running_tests: ask whether to run the tests before running them Returns: bool: True if all tests pass and false otherwise. @@ -149,6 +153,17 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch): test_names = ["{}.{}".format(arguments.tests_path, test) for test in tests_to_run] with modified_environment(**settings), device_launchers: + if ask_before_running_tests: + print("Run tests? [Y/N]: {}".format(test_names)) + while True: + answer = six.moves.input() + if answer == "" or answer.upper()[0] not in ["N", "Y"]: + print("Answer must be Y and N") + elif answer.upper()[0] == "N": + print("Not running tests") + return + elif answer.upper()[0] == "Y": + break runner = xmlrunner.XMLTestRunner(output='test-reports', stream=sys.stdout, failfast=failfast_switch) @@ -191,6 +206,9 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch): Default is in the tests folder of this repo""") parser.add_argument('-f', '--failfast', action='store_true', help="""Determines if the rest of tests are skipped after the first failure""") + parser.add_argument('-a', '--ask_before_running', action='store_true', + help="""Ask if test should be run after emmualtor and ioc started, to allow you to connect + debugger etc""") arguments = parser.parse_args() @@ -220,9 +238,10 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch): tests = arguments.tests if arguments.tests is not None else package_contents(arguments.tests_path) failfast = arguments.failfast + ask_before_running_tests = arguments.ask_before_running try: - success = load_and_run_tests(tests, failfast) + success = load_and_run_tests(tests, failfast, ask_before_running_tests) except Exception as e: print("---\n---\n---\nAn Error occurred loading the tests: ") traceback.print_exc() diff --git a/tests/galil.py b/tests/galil.py new file mode 100644 index 000000000..a4b50ec8c --- /dev/null +++ b/tests/galil.py @@ -0,0 +1,64 @@ +import unittest +import os + +from utils.channel_access import ChannelAccess +from utils.ioc_launcher import IOCRegister, get_default_ioc_dir +from utils.test_modes import TestModes +from utils.testing import parameterized_list, ManagerMode +from parameterized import parameterized + +MTR_01 = "GALIL_01" + + +# Tests will fail if JAWS support module is not up to date and built +test_config_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), "test_config")) + +IOCS = [ + { + "name": MTR_01, + "directory": get_default_ioc_dir("GALIL"), + "pv_for_existence": "AXIS1", + "macros": { + "MTRCTRL": "01", + "GALILCONFIGDIR": test_config_path.replace("\\", "/"), + }, + }, + { + "name": "INSTETC", + "directory": get_default_ioc_dir("INSTETC") + } +] + +TEST_MODES = [TestModes.DEVSIM] + + +class GalilTests(unittest.TestCase): + + """ + Tests for galil motors + """ + def setUp(self): + self._ioc = IOCRegister.get_running("jaws") + self.ca = ChannelAccess(default_timeout=30) + + @parameterized.expand(["Variable", "Frozen"]) + def test_GIVEN_ioc_started_WHEN_set_position_to_THEN_motor_position_set(self, expected_frozen_offset): + expected_postion = 100 + expected_offset = 0 + self.ca.set_pv_value("MOT:MTR0101.OFF", expected_offset) + self.ca.set_pv_value("MOT:MTR0101.FOFF", expected_frozen_offset) + self.ca.set_pv_value("MOT:MTR0101", 0) + self.ca.assert_that_pv_is("MOT:MTR0101", 0, timeout=120) + self.ca.assert_that_pv_is("MOT:MTR0101.RBV", 0) + + with ManagerMode(self.ca): + self.ca.set_pv_value("MOT:MTR0101_SET_POSITION_IN_CONTROLLER", expected_postion) + + # set short timeout so that ensure motor doesn't actually move + # we do expected dmov to go 1,0,1 + self.ca.assert_that_pv_is("MOT:MTR0101", expected_postion, timeout=1) + self.ca.assert_that_pv_is("MOT:MTR0101.RBV", expected_postion, timeout=1) + + self.ca.assert_that_pv_is("MOT:MTR0101.OFF", expected_offset) + self.ca.assert_that_pv_is("MOT:MTR0101.SET", "Use") + self.ca.assert_that_pv_is("MOT:MTR0101.FOFF", expected_frozen_offset) diff --git a/utils/channel_access.py b/utils/channel_access.py index 9eb308dd8..602ed84c1 100644 --- a/utils/channel_access.py +++ b/utils/channel_access.py @@ -34,7 +34,7 @@ class _MonitorAssertion: """ def __init__(self, channel_access, pv): """ - Initilise. + Initialise. Args: channel_access: channel_access to set up monitor pv: name of pv to monitor From ae8fd0120f3de2265aaa6d813529c95df780fb21 Mon Sep 17 00:00:00 2001 From: John-Holt-Tessella Date: Thu, 12 Sep 2019 17:15:05 +0100 Subject: [PATCH 2/4] Remove incorrect comment --- tests/galil.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/galil.py b/tests/galil.py index a4b50ec8c..2471c0615 100644 --- a/tests/galil.py +++ b/tests/galil.py @@ -9,8 +9,6 @@ MTR_01 = "GALIL_01" - -# Tests will fail if JAWS support module is not up to date and built test_config_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), "test_config")) IOCS = [ From 0d8673b7fdb4f338348ccd999e382c4753875dc8 Mon Sep 17 00:00:00 2001 From: John-Holt-Tessella Date: Mon, 23 Sep 2019 13:15:51 +0100 Subject: [PATCH 3/4] remove galil which is no longer needed for this ticket --- tests/galil.py | 62 -------------------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 tests/galil.py diff --git a/tests/galil.py b/tests/galil.py deleted file mode 100644 index 2471c0615..000000000 --- a/tests/galil.py +++ /dev/null @@ -1,62 +0,0 @@ -import unittest -import os - -from utils.channel_access import ChannelAccess -from utils.ioc_launcher import IOCRegister, get_default_ioc_dir -from utils.test_modes import TestModes -from utils.testing import parameterized_list, ManagerMode -from parameterized import parameterized - -MTR_01 = "GALIL_01" - -test_config_path = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), "test_config")) - -IOCS = [ - { - "name": MTR_01, - "directory": get_default_ioc_dir("GALIL"), - "pv_for_existence": "AXIS1", - "macros": { - "MTRCTRL": "01", - "GALILCONFIGDIR": test_config_path.replace("\\", "/"), - }, - }, - { - "name": "INSTETC", - "directory": get_default_ioc_dir("INSTETC") - } -] - -TEST_MODES = [TestModes.DEVSIM] - - -class GalilTests(unittest.TestCase): - - """ - Tests for galil motors - """ - def setUp(self): - self._ioc = IOCRegister.get_running("jaws") - self.ca = ChannelAccess(default_timeout=30) - - @parameterized.expand(["Variable", "Frozen"]) - def test_GIVEN_ioc_started_WHEN_set_position_to_THEN_motor_position_set(self, expected_frozen_offset): - expected_postion = 100 - expected_offset = 0 - self.ca.set_pv_value("MOT:MTR0101.OFF", expected_offset) - self.ca.set_pv_value("MOT:MTR0101.FOFF", expected_frozen_offset) - self.ca.set_pv_value("MOT:MTR0101", 0) - self.ca.assert_that_pv_is("MOT:MTR0101", 0, timeout=120) - self.ca.assert_that_pv_is("MOT:MTR0101.RBV", 0) - - with ManagerMode(self.ca): - self.ca.set_pv_value("MOT:MTR0101_SET_POSITION_IN_CONTROLLER", expected_postion) - - # set short timeout so that ensure motor doesn't actually move - # we do expected dmov to go 1,0,1 - self.ca.assert_that_pv_is("MOT:MTR0101", expected_postion, timeout=1) - self.ca.assert_that_pv_is("MOT:MTR0101.RBV", expected_postion, timeout=1) - - self.ca.assert_that_pv_is("MOT:MTR0101.OFF", expected_offset) - self.ca.assert_that_pv_is("MOT:MTR0101.SET", "Use") - self.ca.assert_that_pv_is("MOT:MTR0101.FOFF", expected_frozen_offset) From 5ddf93bd6dcda5354b4b5e7bd1f6c9de8412a277 Mon Sep 17 00:00:00 2001 From: Alistair McGann Date: Tue, 24 Sep 2019 14:35:55 +0100 Subject: [PATCH 4/4] Move prompt to helper function --- run_tests.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/run_tests.py b/run_tests.py index 55b9d4c6a..5b7f63ab9 100644 --- a/run_tests.py +++ b/run_tests.py @@ -129,6 +129,28 @@ def load_and_run_tests(test_names, failfast, ask_before_running_tests): return all(test_result is True for test_result in test_results) +def prompt_user_to_run_tests(test_names): + """ + Utility function to ask the user whether to begin the tests + + Args: + test_names: List of IOC test names to be run + + Returns: + None + + """ + print("Run tests? [Y/N]: {}".format(test_names)) + while True: + answer = six.moves.input() + if answer == "" or answer.upper()[0] not in ["N", "Y"]: + print("Answer must be Y or N") + elif answer.upper()[0] == "N": + print("Not running tests, emulator and IOC only. Ctrl+c to quit.") + elif answer.upper()[0] == "Y": + return + + def run_tests(prefix, tests_to_run, device_launchers, failfast_switch, ask_before_running_tests=False): """ Runs dotted unit tests. @@ -154,16 +176,7 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch, ask_befor with modified_environment(**settings), device_launchers: if ask_before_running_tests: - print("Run tests? [Y/N]: {}".format(test_names)) - while True: - answer = six.moves.input() - if answer == "" or answer.upper()[0] not in ["N", "Y"]: - print("Answer must be Y and N") - elif answer.upper()[0] == "N": - print("Not running tests") - return - elif answer.upper()[0] == "Y": - break + prompt_user_to_run_tests(test_names) runner = xmlrunner.XMLTestRunner(output='test-reports', stream=sys.stdout, failfast=failfast_switch) @@ -206,9 +219,9 @@ def run_tests(prefix, tests_to_run, device_launchers, failfast_switch, ask_befor Default is in the tests folder of this repo""") parser.add_argument('-f', '--failfast', action='store_true', help="""Determines if the rest of tests are skipped after the first failure""") - parser.add_argument('-a', '--ask_before_running', action='store_true', - help="""Ask if test should be run after emmualtor and ioc started, to allow you to connect - debugger etc""") + parser.add_argument('-a', '--ask-before-running', action='store_true', + help="""Pauses after starting emulator and ioc. Allows you to use booted + emulator/IOC or attach debugger for tests""") arguments = parser.parse_args()